How do you implement a container for different types in Go? [duplicate]

<div class="question-status question-originals-of-duplicate">

This question already has an answer here:

    <li> What would generics in Go be? <span class="question-originals-answer-count"> 2 answers </span> </li> </ul>

    The following code implements a List of ints in Go:

    package main import "fmt" type List struct { Head int Tail *List } func tail(list List) *List { return list.Tail } func main() { list := List{Head: 1, Tail: &List{Head: 2, Tail: &List{Head: 3, Tail: nil}}} fmt.Println(tail(list).Head) }

    Problem is this only works for int. If I wanted a list of strings, <strong>I'd need to re-implement every list method (such as tail) again!</strong> That's obviously not practical, so, this can be solved by using an empty interface:

    type List struct { Head interface{} // Now works for any type! Tail *List }

    Problem is, 1. this seems to be much slower because of type casts, 2. it throws aways type safety, allowing one to type-check anything:

    // This type-checks! func main() { list := List{Head: 123456789 , Tail: &List{Head: "covfefe" , Tail: &List{Head: nil , Tail: &List{Head: []int{1,2}, Tail: nil}}}} fmt.Println(tail(list).Head)

    Obviously that program should not type-check in a statically typed language.

    How can I implement a List type which doesn't require me to re-implement all List methods for each contained type, but which keeps the expected type safety and performance?

    Answer1:

    Go doesn't have generic types, so you're stuck with the options you listed. Sorry.

    Meanwhile, Go's built-in maps and slices, plus the ability to use the empty interface to construct containers (with explicit unboxing) mean in many cases it is possible to write code that does what generics would enable, if less smoothly.

    If you know more about the elements you want to store in the container, you may use a more specialized interface type (instead of the empty interface interface{}), which

      <li>could help you avoid using type assertions (<strong>keep good performance</strong>)</li> <li>and still <strong>keep type safety</strong></li> <li>and it can be used for all types that (implicitly) implement your interface (<strong>code "re-usability"</strong>, no need to duplicate for multiple types).</li> </ul>

      But that's about it. See an example of this here: Why are interfaces needed in Golang?

      Also just in case you missed it, the standard library already has a doubly linked list implementation in the container/list package (which also uses interface{} type for the values).

      Answer2:

      It's important to acknowledge that we expect generic types to be slower, not faster. The excellent fastutil library for Java outperforms the more flexible classes from the standard library by using concrete implementations.

      Russ Cox (one of Go's authors) summarises the situation like this:

        <li>(The C approach.) Leave them out.
          <li>This slows programmers. </li> </ul></li> <li>(The C++ approach.) Compile-time specialization or macro expansion.
            <li>This slows compilation. </li> </ul></li> <li>(The Java approach.) Box everything implicitly.
              <li>This slows execution.</li> </ul></li> </ul>

              You may be interested in this living document which has a lot of the pros and cons outlined.

              As the other answer points out, Go does not support the design you're trying to achieve here. Personally, I'd just duplicate the code - it's not much, the tests are cheap, and most of the time you don't actually need the generic behaviour you want to implement.

              Answer3:

              As icza mentioned there isn't a straightforward way.

              You could try using code generation to generate methods for new types.

              人吐槽 人点赞

Recommend

  • How to rebuild newlib and newlib-nano of GNU Arm Embedded Toolchain
  • Server Side Includes vs. ASP.NET Techniques is there a performance difference?
  • Eclipse not using jars from add classpath variable
  • Jquery - Copy div contents to clipboard
  • Unit Testing the IoC container itself
  • SQLCipher iOS OpenSSL Build error: line 66: ./config: No such file or directory
  • Updating UITableView that is managed by NSFetchedResultsController and has 1 extra cell in the first
  • How to extract the color of a rectangle in a PDF, with iText
  • Matlab: Find area enclosed by points (x,y)
  • Add-Type in a function contained in a module
  • Bind ajax request to specific element Rails 3.1
  • Find XmlNode where attribute value is contained in string
  • Predict/estimate values using randomForest in R
  • PowerShell understand Get-Member
  • Hudson: What is a good way to store a variable between the two job runs?
  • rvest package - Is it possible for html_text() to store an NA value if it does not find an attribute
  • Delayed “rendering” of WPF/Silverlight Dependency Properties?
  • What is 1NF truly?
  • Apache POI 3.17 in OSGi
  • When functionalities of html attributes and css styles overlap
  • Get Original Source code of the URL in Webbrowser Control
  • “Where” statement: match a single word (not substring)
  • Custom perl installation cannot find Git.pm
  • dreferencing 2 d array
  • Android: playing audio files in /res/raw by file name
  • Writing Unittest for generic classes… best approach?
  • FluentMigrator Failed Migrations Don't Rollback?
  • Microsoft Chart Controls for Microsoft .NET Framework 4.0
  • How to get ATL support into an existing Windows application
  • Efficient algorithm to find additions and removals from 2 collections
  • include dlls in visual studio c++ 2008
  • KnockoutObservableArray with typed elements in TypeScript
  • Android activity accessing service's static reference before the service is ready
  • Row Count Is Returning the incorrect number using RaptureXML
  • Switching to Release Build causes runtime error in Web Reference
  • Exception “firebase.functions() takes … no argument …” when specifying a region for a Cloud Function
  • Algorithm for a smudge tool?
  • Is my CUDA kernel really runs on device or is being mistekenly executed by host in emulation?
  • Spray.io: When (not) to use non-blocking route handling?
  • Is possible to count alias result on mysql
  • Check if a string to interpolate provides expected placeholders
  • Cannot Parse HTML Data Using Android / JSOUP
  • C# - Getting references of reference
  • Checking variable from a different class in C#
  • Comment

    用户名: 密码:
    验证码: 匿名发表

    你可以使用这些语言

    查看评论:How do you implement a container for different types in Go? [duplicate]