go语言泛型
go语言中的泛型
Go 1.18版本增加了对泛型的支持。泛型是Go自第一个开源版本以来所做的最大改变。
泛型是一种编写代码的方式,它独立于正在使用的特定类型。函数和类型现在可以被写成使用一组类型中的任何一种。
Type Parameters 类型参数
一个比大小函数例子
func SMin(x, y int) int {
if x < y {
return x
}
return y
}
如果我们希望这个函数不仅仅可以用来比较int类型的参数,我们可以通过添加一个类型参数列表来让这个函数通用化-使其适用于不同的类型:
import "golang.org/x/exp/constraints"
func GMin[T constraints.Ordered](x, y T) T {
if x < y {
return x
}
return y
}
其中的constraints.Ordered作为一个接口,定义如下:
// Ordered is a constraint that permits any ordered type: any type
// that supports the operators < <= >= >.
// If future releases of Go add new ordered types,
// this constraint will be modified to include them.
type Ordered interface {
Integer | Float | ~string
}
他是多种数据类型的一个集合,可以让函数的参数多样化。这样我们无需实现适用于不同类型的函数,实现泛型。
泛型的语法
实际上,在golang中,泛型是从接口中演化而来的。
type Man interface {
Say()
}
type student struct{}
// student实现Say方法
func (s student) Say() {}
// 面向接口编程
func f1(a Man) {}
//强用泛型,多此一举
func f2[T Man](a T) {}
其中的中括号里面,T相当于在这个函数中给Man起了一个别名,实际上T和Man是等价的。
在我们开始提到的例子中,有这样一种写法:
// Signed is a constraint that permits any signed integer type.
// If future releases of Go add new predeclared signed integer types,
// this constraint will be modified to include them.
type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
这里实际上实现了一个联合类型,也就是说Singned包含其中声明的类型, ~int这个语法表示包含一切底层是int32的类型,例如rune
泛型类型
上面,我们介绍了泛型函数:即函数可以接受任意类型。注意和 interface{} 这样的任意类型区分开,泛型中的类型,在函数内部并不需要做任何类型断言和反射的工作,在编译期就可以确定具体的类型。
我们知道,Go 支持自定义类型,比如标准库 sort 包中的 IntSlice:
type IntSlice []int
此外,还有 StringSlice、Float64Slice 等,一堆重复代码。如果我们能够定义泛型类型,就不需要定义这么多不同的类型了。比如:
type Slice[T any] []T
能看懂吧。
在使用时,针对 int 类型,就是这样:
x := Slice[int]{1, 2, 3}
如果作为函数参数,这么使用:
func PrintSlice[T any](b Slice[T])
如果为这个类型定义方法,则是这样:
func (b Slice[T]) Print()
也就是说,Slice[T] 作为整体存在。
当然,泛型类型也可以做类型约束,而不是 any 类型:
type Slice[T comparable] []T