Golang1.21类型推断增强
目录
官方说明⌗
官方说明比较抽象,以下通过例子来说明实际的变化。
部分初始化的泛型函数(Partially instantiated generic functions)⌗
如以下示例,IsEven
是个泛型函数,可以作为非泛型函数Any
和泛型函数AnyGeneric
的参数。
func IsEven[T int | int8 | int16](n T) bool {
return n%2 == 0
}
func Any(numbers []int, fn func(int) bool) bool {
for _, v := range numbers {
if fn(v) {
return true
}
}
return false
}
func AnyGeneric[T any](numbers []T, fn func(T) bool) bool {
for _, v := range numbers {
if fn(v) {
return true
}
}
return false
}
在Go1.21中,我们可以这些调用
// This works in Go 1.21
// In Go 1.20, you will get:
// "cannot use generic function IsEven without instantiation"
anyEven := Any(numbers, IsEven)
anyEven = AnyGeneric(numbers, IsEven)
而在Go1.20中,我们只能这么写
anyEven := Any(numbers, IsEven[int])
anyEven = AnyGeneric(numbers, IsEven[int])
Go1.21可以从函数的泛型参数中推导出AnyGeneric
类型参数的实际类型。
接口赋值给接口(interface assignment interface)⌗
如下面的例子,接口RandomElement
返回一个随机数。它有一个泛型实现MyList
,也有一个非泛型的实现IPSet
。 MustRandom
是个泛型函数,会消费该接口,使用该接口返回一个随机数,如果没有数据,就panic。
type RandomElement[T any] interface {
// 返回一个随机数
RandomElement() (T, bool)
}
func MustRandom[T any](collection RandomElement[T]) T {
val, ok := collection.RandomElement()
if !ok {
panic("collection is empty")
}
return val
}
// MyList 是自定义的泛型类型
type MyList[T any] []T
func (l MyList[T]) RandomElement() (T, bool) {
if len(l) == 0 {
var zero T
return zero, false
}
// assume the 0 is a random number
return l[0], true
}
// IPSet是个具体类型
type IPSet map[netip.Addr]bool
func (s IPSet) RandomElement() (netip.Addr, bool) {
for k := range s {
// assume the first element is a random element
return k, true
}
return netip.Addr{}, false
}
在Go1.21中可以这么写
// 作为调用方MustRandom函数,可以从参数类型推断出泛型函数的类型
// In Go 1.20, you will get:
// "type MyList[int] of MyList[int]{…} does not match RandomElement[T] (cannot infer T)"
randomInt := MustRandom(MyList[int]{1, 2, 3})
var ipSet = make(IPSet)
ipSet[netip.Addr{}] = true
// // In Go 1.20, you will get:
// // "type IPSet of ipSet does not match RandomElement[T] (cannot infer T)"
randomIP := MustRandom(ipSet)
而在Go1.20中,我们只能这么写
// In Go 1.20 you would have to do:
// 调用方和传入参数的泛型函数都需要明确指明实际类型
randomInt := MustRandom[int](MyList[int]{1, 2, 3})
randomIP := MustRandom[netip.Addr](ipSet)
Go1.21之后,调用方函数MustRandom
知道自己的T
和RandomElement
是一样的,而RandomElement
在传入参数中知道自己的类型是int
,MustRandom
自然也能推导出类型参数的具体类型是什么了。
对无类型常量的类型推断(Type inference for untyped constants)⌗
如以下的例子,泛型函数Add
的参数可能是int
,也可能是float64
。这里的T
就是个untyped constants
。
func Add[T int | float64](a, b T) T {
return a + b
}
在go语言中,如下的x, y都是typed常量,我们知道x是int,而y是float64
var x = 1 + 2
var y = 1 + 2.5
但是以下的方法调用,在Go1.20之前,会造成运行时失败,但在Go1.21之后就可以正常推断出z
的类型是float64
。
// In Go 1.20, you will get:
// default type float64 of 2.5 does not match inferred type int for T
var z = Add(1, 2.5)
参考⌗
Read other posts