封面PID=98135423
Go自从1.18开始正式支持了泛型,官方称其为Go开源发布之后最大的一次变更。
在出现泛型之前,Go传递不定参数的通用方法是传递接口,这次支持泛型无疑是对Go编码影响巨大的升级。
本文针对学习过程中的一些要点做初步记录。
泛型
Go支持了泛型,为其带来了三个新的特性:
- Type parameters for function and types.
- Defining interface types as sets of types, including types that don’t have methods.
- Type inference, which permits omitting type arguments in many cases when calling a function.
简单来说,就是支持了函数、type关键字的类型参数,使用无方法接口实现类型集,函数调用泛型推理省略类型参数。
以下是参照Go的官方例子做的示例:
|
|
Hit:
- 类型参数用
[]来进行定义,泛型标识符T。 - Go的编译器会在替换泛型标识符后检查实际类型是否满足函数的类型约束条件。
|
|
其中Go在进行编译时会进行类型推算(type inference),因此你也可以将你的函数写成:
|
|
以上是一个简单的Go泛型函数调用,其中我们可以看到Go使用了接口关键字interface关键字来定义泛型的约束类型。
接下来我们就说说为啥Go是用interface来定义泛型的约束类型集。
泛型约束集
接口定义了一系列方法,实现了这些方法的type可以表现成type->接口的一种映射关系;从另一个角度上来说,接口同样定义了一个实现了这些方法的type的集合,这个集合中的type都实现了接口的方法。因此我们反过来可以获得接口->type的映射关系

官方博客里的这张图片里展示了一个接口在被多个type实现时所具有的集合关系,其中每一个圈都是一个接口的方法集。可以看到,typeP、Q、R在实现了interface后,会在中心区域有一个“方法交集”。这个交集反过来定义了下图的类型集。

一般的接口是方法的接口,这里泛型的接口可以理解为类型的接口。
Go的泛型还支持指定某个Underlying Type,例如:
|
|
上述代码中,~int表示所有以int为Underlying Type的类型。
泛型的Core Type
需要注意的是Go的在使用内置函数的时候需要确定类型的Core Type,比如使用make、range等操作。如果你的泛型interface没有Core Type,你会看到类似如下报错
|
|
这是因为Go定义类型接口的Core Type只在两种情况存在:
- 接口类型集存在统一的Underlying Type
- 接口类型集存在统一的管道,管道的类型、方向需一致
像上面的代码,NumberSlice由于不存在相同的Underlying Type,因此不具有Core Type,不能使用range关键字进行操作。不过我们可以通过调整泛型来实现相同的功能:
|
|
这样就可以正常的实现遍历泛型slice了。
相关文档: