前言
2021.12.14日,Go官方正式发布了支持泛型的Go 1.18beta1版本,这是Go语言自2007年诞生以来,最重大的功能变革。
泛型核心就3个概念:
-
Type parameters for functions and types
类型参数,可以用于泛型函数以及泛型类型
-
Type sets defined by interfaces
Go 1.18之前,interface用来定义方法集( a set of methods)。
Go 1.18开始,还可以使用interface来定义类型集(a set of types),作为类型参数的Type constraint(类型限制)
-
Type inference
类型推导,可以帮助我们在写代码的时候不用传递类型实参,由编译器自行推导。
注意:类型推导并不是永远都可行。
Type parameters(类型参数)
[P, Q constraint1, R constraint2]
这里定义了一个类型参数列表(type parameter list),列表里可以包含一个或者多个类型参数。
P,Q
和R
都是类型参数,contraint1
和contraint2
都是类型限制(type constraint)。
-
类型参数列表使用方括号
[]
-
类型参数建议首字母大写,用来表示它们是类型
先看一个简单示例:
func min(x, y float64) float64 { if x < y { return x } return y }
这个例子,只能计算2个float64
中的较小者。有泛型之前,如果我们要支持计算2个int或者其它数值类型的较小者,就需要实现新的函数、或者使用interface{}
,或者使用Refelect
。
对于这个场景,使用泛型代码更简洁,效率也更优。支持比较不同数值类型的泛型min函数实现如下:
func min(T constraints.Ordered) (x, y T) T { if x < y { return x } return y } // 调用泛型函数 m := min[int](2, 3)
注意:
-
使用
constraints.Ordered
类型,需要import constraints
。 -
min[int](2, 3)
是在对泛型函数min
实例化(instantiation),在编译期将泛型函数里的类型参数T
替换为int
。
instantiation(实例化)
泛型函数的实例化做2个事情
-
把泛型函数的类型参数替换为类型实参(type argument)。
比如上面的例子,min函数调用传递的类型实参是
int
,会把泛型函数的类型参数T
替换为int
-
检查类型实参是否满足泛型函数定义里的类型限制。
对于上例,就是检查类型实参
int
是否满足类型限制constraints.Ordered
。
任何一步失败了,那泛型函数的实例化就失败了,也就是泛型函数调用就失败了。
泛型函数实例化后就生成了一个非泛型函数,用于真正的函数执行。
上面的min[int](2, 3)
调用还可以替换为如下代码:
func min(T constraints.Ordered) (x, y T) T { if x < y { return x } return y } // 方式1 m := min[int](2, 3) // 方式2 fmin := min[int] m2 := fmin(2, 3)
min[int](2, 3)
会被编译器解析成(min[int])(2, 3)
,也就是
-
先实例化得到一个非泛型函数
-
然后再做真正的函数执行。
generic types(泛型类型)
类型参数除了用于泛型函数之外,还可以用于Go的类型定义,来实现泛型类型(generic types)。
看如下代码示