在响了数所后,Go的泛型终于正式落地 1.18 版本。而本次更新中最引人注目的无疑就是泛型的引入。虽然Go创始人反对泛型,但最后还是来了。
一、泛型
1.简单的泛型
func Add[T int|float64] (a, b T) T {
return a + b
}
func main() {
fmt.Println(Add(12, 22))
}
如上述代码中,函数 Add 后的方括号内,即是泛型的定义。该函数定义了一个泛型 T 可以为 int 或 float 。当然也可以加上更多,使用 | 隔开即可。
可是如果泛型可用的类型很多,那函数的定义岂不是会变的很臃肿?
当然,也有办法。
type Addable interface {
uint|int|flaot64|float32
}
func Add[T Addable] (a, b T) T {
return a + b
}
func main() {
fmt.Println(Add(12, 22))
}
由此可见,泛型是可以放在接口内的。
2.字典上的泛型
在官方文档的示例中,使用了字典来介绍泛型
type Number interface {
int64 | float64
}
func SumNumbers[K comparable, V Number](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
comparable 是 1.18 内置的一个新接口,源码定义如下
//comparable 是由所有可比较类型实现的接口
//(布尔、数字、字符串、指针、信道、数组、等类型均为可 comparable 的实例)。
//comparable 接口只能用作泛型约束,不可作为变量的类型。
type comparable interface{ comparable }
在加头看上述的 SumNumbers
函数,其定义了两个泛型,K 和 V,而 K 和 V 可能组成的 map 有很多,比如 map[string]int
或 map[string]float64
在或者 map[int]int
等等。
当然,我们在调用 SumNumbers
时,也可定义其好它的类型。比如:SumNumbers[int, float64](map[int]float64{})
但大多数情况下,我们并不用手动去告诉编译器我们所用的类型,因为它会自动判断类型。
package main
import "fmt"
type Number interface {
int64 | float64
}
func main() {
// Initialize a map for the integer values
ints := map[string]int64{
"first": 34,
"second": 12,
}
// Initialize a map for the float values
floats := map[string]float64{
"first": 35.98,
"second": 26.99,
}
fmt.Printf("Non-Generic Sums: %v and %v\n",
SumInts(ints),
SumFloats(floats))
fmt.Printf("Generic Sums: %v and %v\n",
SumIntsOrFloats[string, int64](ints),
SumIntsOrFloats[string, float64](floats))
fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
SumIntsOrFloats(ints),
SumIntsOrFloats(floats))
fmt.Printf("Generic Sums with Constraint: %v and %v\n",
SumNumbers(ints),
SumNumbers(floats))
}
// 未使用泛型的函数。
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
}
// 使用泛型
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
func SumNumbers[K comparable, V Number](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}