泛型
May 30, 2022
泛型 #
是什么? #
Type parameter, 类型参数。func Add[T Number](x, y T) (r T)
,其中的T
就是类型参数,它被接口Number
所约束。
type Number interface {
int | float32
}
调用方除了可自行决定参数值之外,还可以自行决定参数类型。Add[int](1, 2)
,在调用时指定T
的类型为int
,同时传入参数值1
,2
必须是int
类型。
这样使得代码更灵活,更有扩展性,同时更安全。
Go泛型 #
为什么? #
静态语言,类型固定,比如这个函数:func Add(x, y int) int
就要求参数和结果都必须是整型。
那如果后来又需要一个浮点数的加法呢?
那使用interface{}不也可以吗?
试看:
// 准确的描述出了参数和返回值的类型,非常方便
func Add(x, y int) int
// 但也限制了Add函数的参数类型--只能接收`int`
// Add(0.1, 0.2) // can't do that
// 那怎么办呢?再写一个针对float64的呗
func AddFloat64(x, y float64) float64
AddFloat64(0.1, 0.2) // it's ok
// 如果还要支持其它类型呢?再加一个吗,每多一种类型,就多加一个。。。
func AddInt8(x, y int8) int8
func AddInt32(x, y int32) int32
func AddFloat32(x, y float32) float32
// more...
// emm.
// how about interface{}?
func AddAny(x, y interface{}) interface{} {
switch x.(type) {
case int:
case int8:
case int32:
case float32:
case float64:
// more...
default:
panic("not support type")
}
}
// interface{}表示可以接收任意类型的值,并且返回任意类型的值
// 换言之,参数的类型和返回值的类型没有必然联系--从签名看来,它们可以一样,也可以不一样
// 所以,使用interface{}不够安全。
func AddGeneric1[T any](x, y T) T // 看起来跟AddAny差不多,但是参数类型和返回值类型必然是相同的
// 但any并不一定支持+运算符,所以需要用更细粒度的约束
type Number interface {
~int|~int8|~int32|~float32|~float64
}
func AddGeneric2[T Number](x, y T) T // 通过Number约束,确保类型参数可加
// 泛型的存在,使得函数的类型集比any小,比int大;使得返回值和参数的类型能够动态联系。
func Map[T, E any](list []T, f func(T) E) []E {
r := make([]E, len(list))
for i := range list {
r[i] = f(list[i])
}
return r
}