Golang泛型
- 安装go1.18或更高版本
- 创建一个go项目,新建main.go
1. 什么是泛型
一种类型的约束。
2. 非泛型函数
以map[string]
为例,求 map[string]int64
和 map[string]float64
的value和。
// 非泛型函数
func sumInts(m map[string]int64) int64 {
var s int64
for _, v := range m {
s += v
}
return s
}
func sumFloats(m map[string]float64) float64 {
var s float64
for _, v := range m {
s += v
}
return s
}
在main函数中添加如下代码:
m1 := map[string]int64{
"one": 1,
"two": 2,
"three": 3,
}
m2 := map[string]float64{
"one": 1.1,
"two": 2.2,
"three": 3.3,
}
// 非泛型测试
fmt.Printf("Non-Generic Sums: %v and %v\n\n",
sumInts(m1),
sumFloats(m2))
运行代码
$ go run .
Non-Generic Sums: 6 and 6.6
3. 泛型函数
在 main.go
中添加
// 泛型函数
func sumNumbers[K comparable, V int64 | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
在该函数签名中
-
声明了两个泛型约束:
K comparable
和V int64 | float64
-
K作为map的key类型约束,要求其类型必须是可比较的,而
comparable
是 go为可比较泛型定义的约束其底层为
type comparable interface{ comparable }
-
V约束代表允许
int64
和float64
两种类型,用|
隔开
在main函数中添加如下代码:
// 泛型测试
fmt.Printf("Non-Generic Sums: %v and %v\n\n",
sumNumbers(m1),
sumNumbers(m2))
运行
$ go run .
Non-Generic Sums: 6 and 6.6
Generic Sums: 6 and 6.6
可以看到泛型是代码更简洁方便!
4. 声明类型约束
接下来,将通过将整数和浮点数的并集捕获到可以重用的类型约束(例如从其他代码中)来进一步简化函数。
在main.go import语句下方添加如下代码:
// 声明类型约束
type Number interface {
int64 | float64
}
我们将上一个例子的泛型函数的Valeu类型约束抽离出来,使得可复用。
接下来将泛型函数签名改为如下形式:
func sumNumbers[K comparable, V Number](m map[K]V) V
类型约束也可以嵌套声明
如:
type Integer interface {
~int | ~int8 | ~int32 | ~int64
}
type Float interface {
~float32 | ~float64
}
// Number 声明类型约束
type Number interface {
Integer | Float
}
在Number
约束中,使用了 Integer
和 Float
约束。
~ 波浪号
我们会在一些泛型示例中看到这样的声明:
type Number interface {
~int64 | float64 | string
}
这里的 ~
可以理解为泛类型,即所有以int64为基础的类型都能够被约束。
如: type myint int64
5. constraints包
在泛型测试阶段,有一个 constraints
包,包里定义了Signed
,Unsigned
, Integer
, Float
, Complex
和Ordered
共6个interface类型,可以用于泛型里的类型约束(type constraint
)。
但是在go1.18正式版中并没有被发布。