go1.18引入了泛型的语法.

1. 类型的属性

参考: https://go.dev/ref/spec#Type_parameter_declarations

1.1. 底层类型 Underlying types

每个类型T都有一个底层类型

Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its declaration. For a type parameter that is the underlying type of its type constraint, which is always an interface.

type (
    A1 = string     //底层类型是string
    A2 = A1         //底层类型是string
)

type (
    B1 string       //底层类型是string
    B2 B1           //底层类型是string
    B3 []B1         //底层类型是[]B1
    B4 B3           //底层类型是[]B1
)

func f[P any](x P) {}    //P的底层类型是interface{}

在比如~[]byte表示底层类型是[]byte

1.2. 核心类型 core type

  • 每个非interface类型T都有个核心类型, 就是T的底层类型
  • 不是所有的interface T都有核心类型, 有核心类型的T要满足下面任意一项:
    • 如果T的type set只有一个底层类型U, 那么T有核心类型为U
    • 如果T的type set只有相同方向的channel类型, channel的元素是E, 那么T的核心类型是chan E, 或者带方向的chan<- E or <-chan E
  • 其他的interface都没有核心类型

根据以上规则, interface的核心类型不可能是自定义类型, 或者其他的interface类型.

1.2.1. 有core type的interface举例

type Celsius float32
type Kelvin  float32

interface{ int }                          // int
interface{ Celsius|Kelvin }               // float32
interface{ ~chan int }                    // chan int
interface{ ~chan int|~chan<- int }        // chan<- int
interface{ ~[]*data; String() string }    // []*data

1.2.2. 没有core type的interface举例

interface{}                               // no single underlying type
interface{ Celsius|float64 }              // no single underlying type
interface{ chan int | chan<- string }     // channels have different element types
interface{ <-chan int | chan<- int }      // directional channels have different directions

1.2.3. bytestring特殊core type

if there are exactly two types, []byte and string, which are the underlying types of all types in the type set of interface T, the core type of T is called bytestring.

interface{ int }                          // int (same as ordinary core type)
interface{ []byte | string }              // bytestring
interface{ ~[]byte | myString }           // bytestring

2. interface类型

An interface type defines a type set. A variable of interface type can store a value of any type that is in the type set of the interface. Such a type is said to implement the interface. The value of an uninitialized variable of interface type is nil.

就是说一个interface类型实际上表示了一个类型的集合. 一个interface变量就是这个集合中的一个类型的实例. 这个集合中所有的类型都实现了这个interface的要求.

InterfaceType  = "interface" "{" { InterfaceElem ";" } "}" .
InterfaceElem  = MethodElem | TypeElem .
MethodElem     = MethodName Signature .
MethodName     = identifier .
TypeElem       = TypeTerm { "|" TypeTerm } .
TypeTerm       = Type | UnderlyingType .
UnderlyingType = "~" Type .

注意看上面的interface声明的语法:

  • interface不仅可以包含常见的的方法(MethodElem), 还可以包括类型(TypeElem)
  • 类型可以用|表示或
  • ~表示底层类型

An interface type is specified by a list of interface elements. An interface element is either a method or a type element, where a type element is a union of one or more type terms. A type term is either a single type or a single underlying type.

2.1. 带方法的interface

最常见的interface是带方法约束的(可以为空), 比如:

// A simple File interface.
interface {
    Read([]byte) (int, error)
    Write([]byte) (int, error)
    Close() error
}

2.2. interface可以被嵌入其他interface

比如

type Reader interface {
    Read(p []byte) (n int, err error)
    Close() error
}

type Writer interface {
    Write(p []byte) (n int, err error)
    Close() error
}

// ReadWriter's methods are Read, Write, and Close.
type ReadWriter interface {
    Reader  // includes methods of Reader in ReadWriter's method set
    Writer  // includes methods of Writer in ReadWriter's method set
}

2.3. 泛型interface

1.18引入了泛型的概念, 使得interface的概念从方法的约束扩展到了类型的约束, 从而interface可以表达一个类型的集合

比如interface {int}就表示只包括int类型的集合;
再比如interface {~int}就表示底层类型是int的集合, 这个集合就比上面的大.

现在interface可以包括方法, 或类型, 甚至方法和类型的混合, 比如下面的例子表示一个实现了String()方法的底层类型是int的类型

// An interface representing all types with underlying type int that implement the String method.
interface {
    ~int
    String() string
}

interface体里的约束是与的关系, 所以下面的例子表示一个空的集合, 因为没有一个类型既是int, 又是string

// An interface representing an empty type set: there is no type that is both an int and a string.
interface {
    int
    string
}

汇总如下:

// An interface representing only the type int.
interface {
    int
}

// An interface representing all types with underlying type int.
interface {
    ~int
}

// An interface representing all types with underlying type int that implement the String method.
interface {
    ~int
    String() string
}

// An interface representing an empty type set: there is no type that is both an int and a string.
interface {
    int
    string
}

可以使用|表示或, 比如下面的例子表示所有底层类型是float32或float64的类型:

// The Float interface represents all floating-point types
// (including any named types whose underlying types are
// either float32 or float64).
type Float interface {
    ~float32 | ~float64
}

3. 泛型

比如下面的泛型函数:

func min[T ~int|~float64](x, y T) T {
    if x < y {
        return x
    }
    return y
}

函数名后面的方括号里面是类型参数type parameter. 比如下面的都是类型参数:

[P any]
[S interface{ ~[]byte|string }]
[S ~[]E, E any]
[P Constraint[int]]
[_ any]

这里面的any, interface{ ~[]byte|string }学名叫做TypeConstraint
完整的形式应该是interface{...}, 其中interface有时候可以省略, 比如:

[T []P]                      // = [T interface{[]P}]
[T ~int]                     // = [T interface{~int}]
[T int|string]               // = [T interface{int|string}]
type Constraint ~int         // illegal: ~int is not inside a type parameter list

3.1. 类型约束 type constraint

下面的Number就是个类型约束:

type Number interface {
    int64 | float64
}

3.2. 实例化

泛型的函数在使用的时候必须实例化, 比如下面的f := min就不合法, 因为min此时min并不知道入参类型, 无法实例化.
编译器会根据实际的入参类型来推断并实例化泛型函数

func min[T ~int|~float64](x, y T) T {}

f := min                   // illegal: min must be instantiated with type arguments when used without being called
minInt := min[int]         // minInt has type func(x, y int) int
a := minInt(2, 3)          // a has value 2 of type int
b := min[float64](2.0, 3)  // b has value 2.0 of type float64
c := min(b, -1)            // c has value -1.0 of type float64

再比如下面的泛型函数非常典型, 对slice S中的每个元素做apply操作.

func apply[S ~[]E, E any](s S, f(E) E) S {}

f0 := apply[]                  // illegal: type argument list cannot be empty
f1 := apply[[]int]             // type argument for S explicitly provided, type argument for E inferred
f2 := apply[[]string, string]  // both type arguments explicitly provided

var bytes []byte
r := apply(bytes, func(byte) byte {})  // both type arguments inferred from the function arguments

4. 泛型举例

4.1. 使用泛型前

// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
    var s int64
    for _, v := range m {
        s += v
    }
    return s
}

// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
    var s float64
    for _, v := range m {
        s += v
    }
    return s
}

4.2. 使用泛型后

// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}

调用SumIntsOrFloats的时候, 必须让编译器知道如何实例化.

  • 可以显式的指定入参类型: 比如SumIntsOrFloats[string, int64](ints), 或者SumIntsOrFloats[string, float64](floats))
  • 也可以让编译器推断: SumIntsOrFloats(ints), 或者SumIntsOrFloats(floats)

4.3. 使用类型约束让代码更可读

type Number interface {
    int64 | float64
}

// SumNumbers sums the values of map m. It supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}

results matching ""

    No results matching ""