不支持
Feature
Desc
泛型特化
编写一个泛型函数
针对某个具体类型的特殊
版本
元编程
编写在编译时
执行的代码来生成
在运行时
执行的代码
操作符方法
不能将操作符
视为方法
并自定义其实现
变长类型参数
容器 重复代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 func maxInt (sl []int ) int { if len (sl) == 0 { panic ("empty slice" ) } max := sl[0 ] for _, v := range sl[1 :] { if v > max { max = v } } return max } func maxString (sl []string ) string { if len (sl) == 0 { panic ("empty slice" ) } max := sl[0 ] for _, v := range sl[1 :] { if v > max { max = v } } return max }
any 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func maxAny (sl []any) any { if len (sl) == 0 { panic ("empty slice" ) } max := sl[0 ] for _, v := range sl[1 :] { switch v.(type ) { case int : if v.(int ) > max.(int ) { max = v } case string : if v.(string ) > max.(string ) { max = v } } } return max }
builtin/builtin.go
缺陷
基于 type switch
,若要支持其它元素类型,需要修改代码
,不符合开闭原则
返回值为 any
,调用者使用实际类型的值还需要通过 type assertion
转换
any
作为入参和返回值的元素类型,存在装箱
和拆箱
操作,存在性能损耗
1 2 3 4 5 6 7 8 9 10 11 12 13 func BenchmarkMaxInt (b *testing.B) { sl := []int {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 } for i := 0 ; i < b.N; i++ { maxInt(sl) } } func BenchmarkMaxAny (b *testing.B) { sl := []any{1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 } for i := 0 ; i < b.N; i++ { maxAny(sl) } }
1 2 3 4 5 6 7 8 9 10 $ go test -v -bench . goos: darwin goarch: arm64 pkg: github.com/xxx/gc BenchmarkMaxInt BenchmarkMaxInt-10 296372949 4.052 ns/op BenchmarkMaxAny BenchmarkMaxAny-10 120496152 9.954 ns/op PASS ok github.com/xxx/gc 3.822s
泛型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 type ordered interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string } func maxGenerics [T ordered ](sl []T) T { if len (sl) == 0 { panic ("empty slice" ) } max := sl[0 ] for _, v := range sl[1 :] { if v > max { max = v } } return max } type myString string func main () { m := maxGenerics([]int {1 , 2 , 3 , 4 , 5 }) fmt.Printf("%T %v\n" , m, m) fmt.Println(maxGenerics([]int8 {1 , 2 , 3 , 4 , 5 })) fmt.Println(maxGenerics([]myString{"11" , "22" , "44" , "66" , "77" , "10" })) fmt.Println(maxGenerics([]float64 {1.1 , 2.2 , 3.3 , 4.4 , 5.5 })) }
性能要优于 any 版本
1 2 3 4 5 6 7 8 9 10 11 12 $ go test -v -bench . goos: darwin goarch: arm64 pkg: github.com/xxx/gc BenchmarkMaxInt BenchmarkMaxInt-10 293859739 4.052 ns/op BenchmarkMaxAny BenchmarkMaxAny-10 120446469 9.958 ns/op BenchmarkMaxGenerics BenchmarkMaxGenerics-10 214360436 5.602 ns/op PASS ok github.com/xxx/gc 5.585s
类型参数
Go 泛型方案的实质是对类型参数
的支持
Type
Desc
泛型函数
- generic function
带有类型参数的函数
泛型类型
- generic type
带有类型参数的自定义类型
泛型方法
- generic method
与泛型类型
绑定的的方法
泛型函数
[T ordered]
为 Go 泛型的类型参数列表
T 为类型参数,而 ordered 为类型参数
的类型约束
(type constraint
)
1 2 3 func maxGenerics [T ordered ](sl []T) T { }
1 func genericsFunc [T1 constraint1 , ...Tn constraintN ](ordinary parameters list) (return values list)
函数一旦拥有类型参数
,可以用该参数作为常规参数列表和返回值列表中修饰参数
和返回值
的类型
类型参数的名字
的首字母
通常为大写
,并且参数类型必须具名
的
在同一个
类型参数列表中,类型参数的名字
是唯一
的
1 2 3 4 5 func print [T any ]() {} func print [any ]() {} func compare [T1 any , T1 comparable ]() {}
作用域(类型参数的声明顺序
不会影响泛型函数的行为)
调用
类型参数分为类型形参
(type parameter
)和类型实参
(type argument
)
泛型函数中声明
的类型参数为类型形参
,实际调用
泛型函数时传递
(或者编译器自动推导
)的类型为类型实参
1 2 3 4 5 6 7 8 9 func maxGenerics [T ordered ](sl []T) TmaxGenerics[int8 ]([]int8 {1 , 2 , 3 , 4 , 5 }) maxGenerics([]int {1 , 2 , 3 , 4 , 5 })
自动推断
的前提:必须在函数的参数列表
中使用了类型形参
1 2 3 4 5 6 7 func foo [T comparable , E any ](a int , s E) {}func main () { foo[int ](5 , "hello" ) foo[int , string ](5 , "hello" ) foo(5 , "hello" ) }
无法通过返回值类型
来推断类型实参
1 2 3 4 5 6 7 8 9 func foo [T any ]() T { var t T return t } func main () { var a int = foo() println (a) }
调用过程 1 maxGenerics([]int {1 , 2 , -4 , -6 , 7 , 0 })
Go 对泛型函数进行实例化
(Instantiation)
根据自动推断出的类型实参生成一个新函数
在编译阶段
完成,不会影响运行时性能
然后调用新函数对输入的函数参数进行处理
1 2 maxGenericsInt := maxGenerics[int ] fmt.Printf("%T %v\n" , maxGenericsInt, maxGenericsInt([]int {1 , 2 , -4 , -6 , 7 , 0 }))
使用相同类型实参
对泛型函数进行调用,仅会实例化一次
泛型类型
在类型声明
中带有类型参数
的 Go 类型,一般形式如下
1 type TypeName[T1 constraint1, ...Tn constraintN] TypeLiteral
1 2 3 4 5 6 7 8 9 10 type ordered interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string } type maximizableSlice[T ordered] struct { elems []T }
类型参数的作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 type Set[T comparable] map [T]struct {}type sliceFn[T any] struct { s []T cmp func (T, T) bool } type node[K, V any] struct {}type Map[K, V any] struct { root *node[K, V] compare func (K, K) int } type element[T any] struct { next *element[T] val T } type Number interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~complex64 | ~complex128 } type NumericAbs[T Number] interface { Abs() T }
泛型类型内部使用自身,注意顺序
1 2 3 4 5 6 7 type P[T1, T2 any] struct { F *P[T1, T2] } type P[T1, T2 any] struct { F *P[T2, T1] }
使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainimport "fmt" type ordered interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string } type maximizableSlice[T ordered] struct { elems []T } func main () { sl := maximizableSlice[int ]{ elems: []int {1 , 2 , 3 , 4 , 5 }, } fmt.Printf("%T\n" , sl) }
实例化
(Instantiation),根据传入的类型实参
(int)生成一个新类型
,并创建该类型的实例
1 2 3 type maximizableIntSlice struct { elems []int }
泛型类型尚不
支持自行推断
1 2 3 sl := maximizableSlice{ elems: []int {1 , 2 , 3 , 4 , 5 }, }
类型别名
类型别名与其绑定的原类型完全等价
,但仅限于原类型是一个直接类型
,而非泛型类型
1 2 3 4 5 6 7 8 type foo[T1 any, T2 comparable] struct { a T1 b T2 } type coo = foo[int , int ] type bar = foo
泛型类型
只有在完成实例化
后,才能用于声明变量
,才能成为一个直接类型
,才能被用于类型别名
1 2 3 4 type fooInstantiation struct { a int b int }
类型嵌入
可以在泛型类型
定义中嵌入普通类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type Lockable[T any] struct { t T sync.Mutex } func (l *Lockable[T]) Get() T { defer l.Unlock() l.Lock() return l.t } func (l *Lockable[T]) Set(v T) { defer l.Unlock() l.Lock() l.t = v }
可以将其它泛型类型实例化
后的类型作为成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 type Slice[T any] []Tfunc (s Slice[T]) String() string { if len (s) == 0 { return "" } var result = fmt.Sprintf("%v" , s[0 ]) for _, v := range s[1 :] { result = fmt.Sprintf("%v, %v" , result, v) } return result } type Lockable[T any] struct { sync.Mutex Slice[int ] t T } func main () { n := Lockable[string ]{ t: "hello" , Slice: []int {1 , 2 , 3 }, } fmt.Println(n.String()) }
在普通类型定义中,可以使用实例化
后的泛型类型作为成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 type Slice[T any] []Tfunc (s Slice[T]) String() string { if len (s) == 0 { return "" } var result = fmt.Sprintf("%v" , s[0 ]) for _, v := range s[1 :] { result = fmt.Sprintf("%v, %v" , result, v) } return result } type Foo struct { Slice[int ] } func main () { f := Foo{ Slice[int ]{1 , 2 , 3 , 4 , 5 }, } fmt.Println(f.String()) }
类型嵌入
与类型别名
类似,仅限于实例化
后的泛型类型
(成为直接类型
,可以直接用于声明变量
)
泛型方法
泛型类型
定义的方法称为泛型方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 type ordered interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string } type maximizableSlice[T ordered] struct { elems []T } func (sl *maximizableSlice[T]) max() T { if len (sl.elems) == 0 { panic ("slice is empty" ) } max := sl.elems[0 ] for _, elem := range sl.elems[1 :] { if elem > max { max = elem } } return max }
泛型方法
自身不支持类型参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 type ordered interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string } type maximizableSlice[T ordered] struct { elems []T } func (sl *maximizableSlice[T]) max[E any](e E) T { if len (sl.elems) == 0 { panic ("slice is empty" ) } max := sl.elems[0 ] for _, elem := range sl.elems[1 :] { if elem > max { max = elem } } return max }
在泛型方法中,receiver 的某个类型参数如果没有使用
,可以标记为 _
1 2 3 4 5 6 7 8 9 10 11 type foo[A comparable, B any] struct {}func (foo[A, B]) M1() {} func (foo[A, _]) M2() {} func (foo[_, B]) M3() {} func (foo[_, _]) M4() {} func (foo[]) M5() {}
泛型方法中的 receiver 类型参数名字
可以与泛型类型中的类型形参名不同,位置
和数量
对齐即可
1 2 3 type foo[A comparable, B any] struct {}func (foo[First, Second]) M1(a First, b Second) {}