头图

Recently, the official Go blog published an article on the new feature "generics" based on the 2021 GopherCon conference, authored by Robert Griesemer and Ian Lance Taylor.

According to reports, Go 1.18 version added support for generics, which is the biggest change since Go was open sourced. Generics is a writing paradigm that is independent of the specific type used, allowing the use of any type from a collection of types in the implementation of functions and types.

Generics add three new important things to Go:

  1. "type parameters" for functions and types
  2. Defines an interface type as a collection of types, including interface types without methods
  3. Type inference: In many cases, type arguments can be omitted when calling a generic function

type inference

This is the most complex change in Go, including:

  • Function argument type inference
  • Constraint type inference

While the details of how type inference works are complex, using it is not: type inference either succeeds or fails. If successful, the type parameter can be omitted, and calling a generic function looks no different than calling a normal function. If type inference fails, the compiler will give an error message, in which case just provide the necessary type parameters.

type arguments

Now that both functions and types have type parameters, the type parameter list looks like a normal parameter list, except it uses square brackets instead of parentheses.

Let's start with the basic non-generic Min function for floating point values:

 func Min(x, y float64) float64 {
    if x < y {
        return x
    }
    return y
}

Make this function generic by adding a list of type parameters - making it work for different types. In this example, a type parameter list with a single type parameter T is added and float64 is replaced by T .

 import "golang.org/x/exp/constraints"

func GMin[T constraints.Ordered](x, y T) T {
    if x < y {
        return x
    }
    return y
}

This function can now be called with a type parameter

 x := GMin[int](2, 3)

Supplying a type parameter to GMin , in this case int is called instantiation. Instantiation occurs in two steps. First, the compiler replaces all type parameters with their respective type parameters in a generic function or generic type.

Second, the compiler verifies that each type parameter satisfies the respective constraints. If the second step fails, the instantiation fails and the program becomes invalid. Upon successful instantiation, a non-generic function is produced, which can be called like any other function. E.g:

 fmin := GMin[float64]
m := fmin(2.71, 3.14)

Instantiating GMin\[float64\] yields a function equivalent to the Min function, which can be used in function calls. Type parameters can also be used with types.

 type Tree[T interface{}] struct {
    left, right *Tree[T]
    value       T
}

func (t *Tree[T]) Lookup(x T) *Tree[T] { ... }

var stringTree Tree[string]


Here the generic type Tree stores the value of the type parameter T. Generic types can also have methods, as in this example Lookup . In order to use a generic type, it must be instantiated; Tree\[string\] is an example of instantiating Tree d616e52187447b7a65916ed32aad02f4--- with the type parameter string .

Generics is an important new language feature in Go 1.18, and according to Robert Griesemer and Ian Lance Taylor, this feature is well implemented and of high quality, but caution is required when deploying generic code in production.

Original blog post:

https://go.dev/blog/intro-generics


snakesss
1.1k 声望243 粉丝

SegmentFault 思否编辑,欢迎投稿优质技术资讯!