假设我写了这样两个函数:
func ToInterfaceSlice[T any](s []T) []interface{} {
res := make([]interface{}, len(s))
for i, v := range s {
res[i] = v
}
return res
}
func FromInterfaceSlice[T any](s []interface{}) (res []T, err error) {
res = make([]T, len(s))
for i, v := range s {
vt, ok := v.(T)
if !ok {
return nil, fmt.Errorf("%v (type=%T) doesn't fit the target type %T", v, v, res)
}
res[i] = vt
}
return
}
当我从输入参数解析类型时,我可以简单地使用
var m = []int{1, 2, 3}
fmt.Println(ToInterfaceSlice(m))
编译器知道T
是int
。
但是当我尝试从返回变量
传递类型时var m []int
m, _ = FromInterfaceSlice([]interface{}{1, 2, 3})
fmt.Println(m)
编译器给出错误:
划痕。go:29:27: cannot infer T
必须在函数调用中显式传递类型:
var m []int
m, _ = FromInterfaceSlice[int]([]interface{}{1, 2, 3})
fmt.Println(m)
当接收变量不是接口时,从返回类型推断类型参数是否有困难?或者只是不执行,甚至故意不执行?
在注释后更新#1
我知道a, b := GenericFunc()
不能引用返回值的类型。目前Go确实有"视情况而定"。Case是否需要从用户输入显式实例化。
type Set[T comparable] map[T]struct{}
func NewSet[T comparable](eles ...T) Set[T] {
s := make(Set[T])
for _, ele := range eles {
s[ele] = struct{}{}
}
return s
}
可以同时使用t := NewSet(1, 2, 3)
和t := NewSet[string]()
,但现在不能使用var t NewSet[float64] = NewSet()
,因为这个
当前的类型推断规则是显式的。没有考虑返回值的使用方式:
类型推断基于
- a类型参数列表
- 用已知类型参数初始化的替换映射M,如果有
- 普通函数参数列表(可能为空)(仅在函数调用的情况下)
从Go 1.18开始,可以简单地重写函数以接受所需类型的参数;这样做的好处是不会在函数体中隐藏分配:
func FromInterfaceSlice[T any](s []interface{}, dst []T) error {
if len(s) != len(dst) {
return errors.New("lengths don't match")
}
for i, v := range s {
vt, ok := v.(T)
if !ok {
return nil, fmt.Errorf("%v (type=%T) doesn't fit the target type %T", v, v, res)
}
dst[i] = vt
}
return nil
}
并传入具有所需长度的目标切片:
func main() {
src := []interface{}{1, 2, 3}
m := make([]int, len(src))
_ = FromInterfaceSlice(src, m)
fmt.Println(m)
}
如果你不能或不想事先确定切片的长度,你只能使用显式实例化:
var m []int
m, _ = FromInterfaceSlice[int]([]interface{}{1, 2, 3})
// ^^^ explicit type argument
类型参数仍然不能用:=
速记声明来推断:
// what is m???
m, err := FromInterfaceSlice([]interface{}{1, 2, 3})