go 泛型
1. 类型参数(Type parameters)
Go语言的泛型(Generic)叫做类型参数。泛型可以让我们代码适应不同类型的参数。
泛型函数
声明语法
// 声明一个带有泛型的函数
// T 指类型参数,就是一个参数,代表类型
// Constraint 是对类型参数T的约束,限制T的取值, 可以是int、string、any等类型,any可以是任意类型的意思
// s 是要打印的参数
func name[T {Constraint}](s T) {}
函数名和函数参数列表之间插入了一组方括号,来表示类型参数。跟函数参数一样,我们需要为每一个类型参数指定「类型」,这种类型的类型Go语言称之为约束。
示例
// 打印函数
func print[T any](s ...T) {
for _, i := range s {
fmt.Println(i)
}
}
T表是切片成员的类型,但T的实际类型在定义print()的时候是不确定的,需要在调用该函数的时候指明。也就是说,我们在调用print()函数的时候需要额外传入一个特殊参数来指定T的具体类型。这种特殊的参数就叫类型参数。
使用泛型函数
func main() {
// 约束为int类型
print[int](1, 3, 4)
// 约束为string类型
print[string]("derek", "阿瓦达啃大瓜", "奇摩鸡")
// 任意类型
print[any](1, "wo")
// 任意类型,与any一样
print[interface{}](1, "wo")
// 不指定约束类型,则输入的数据类型必须为同一种类型
print(1, 3, 4)
}
指定出参类型
// 指定返回参数的类型是T
func add[T any](a, b T) T {
return a + b
}
// 也可以返回指针
func addV2[T any](a T) *T {
return &a
}
func main() {
// 约束为int类型
add[int](1, 3, 4)
// 约束为string类型
add[string]("derek", "阿瓦达啃大瓜")
}
// 结果输出:
// 8
// derek阿瓦达啃大瓜
泛型类型
// 定义一个泛型的数组
type Nums[T any] []T
// 定义一个泛型的map, map的K比较特殊,必须使用comparable来约束, 否则不生效
type Map[K comparable, V any] map[K]V
2. 内置约束 comparable
泛型参数一般都可以进行运算操作,但有两个符号是特殊的,就是:== 和 !=。 如果参数需要使用这两个作比较,则一定要使用comparable。
// 比较两个参数t、v是否相等
func Comp[T comparable](s []T, v T) int {
for i, t := range s {
if t == v {
return i
}
}
return 0
}
如果把上述的comparable改为any,则会报错:
invalid operation: t == v (type parameter T is not comparable with ==)
map数据的key有需要使用comparable,否则也会报错
3.自定义约束 (Constraint)
泛型的Constraint,可以使用any、int、string、comparable
都可以,还可以定义一个interface来定义约束
// Addable 泛型操作
type Addable interface {
// 约束类型
~int | float32 | ~float64 | string
}
func add[T Addable](a, b T) T {
return a + b
}
上述的"~"
符号不是必须的,但加上"~"
的话,系统会兼容基类参数类型。例如,这里定义了一个类型Int
type Int int
int就是Int的基类类型,如果是这时候Addable
的是~int
,则Int会在其约束范围内,否则不在约束范围内。
并集约束
取约束类型的并集,int
和float32
都是约束
type Addable interface {
int | float32
}
交集约束
type Stringer interface {
String() string
}
type Addable interface {
int
Stringer
}
这种情况下,Addable
约束的类型,必须是int类型,且这个类型实现 Stringer
接口。