是否可以根据分配给 return 值的内容推断类型参数?
Is it possible to infer type parameters from what return values are assigned to?
假设我写了两个这样的函数:
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
。
然而,当我尝试从 return 变量传递类型时
var m []int
m, _ = FromInterfaceSlice([]interface{}{1, 2, 3})
fmt.Println(m)
编译器报错:
.\scratch.go:29:27: cannot infer T
我必须在函数调用中显式传递类型:
var m []int
m, _ = FromInterfaceSlice[int]([]interface{}{1, 2, 3})
fmt.Println(m)
当接收者变量不是接口时,从 return 类型推断类型参数有什么困难吗?还是干脆不执行,甚至故意不执行?
评论后更新#1
我知道 a, b := GenericFunc()
不能引用 returned 值的类型。目前 Go 确实有“这取决于”情况是否需要来自用户输入的显式实例化。
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()
不行,因为这个
类型推断的当前规则是explicit。未考虑如何使用 return 值:
Type inference is based on
- a type parameter list
- a substitution map M initialized with the known type arguments, if any
- a (possibly empty) list of ordinary function arguments (in case of a function call only)
从 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)
}
如果您不能或不想事先确定切片的长度,您只能进行显式实例化。
此外,类型参数仍然无法通过 :=
shorthand 声明推断出来:
// what is m???
m, err := FromInterfaceSlice([]interface{}{1, 2, 3})
假设我写了两个这样的函数:
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
。
然而,当我尝试从 return 变量传递类型时
var m []int
m, _ = FromInterfaceSlice([]interface{}{1, 2, 3})
fmt.Println(m)
编译器报错:
.\scratch.go:29:27: cannot infer T
我必须在函数调用中显式传递类型:
var m []int
m, _ = FromInterfaceSlice[int]([]interface{}{1, 2, 3})
fmt.Println(m)
当接收者变量不是接口时,从 return 类型推断类型参数有什么困难吗?还是干脆不执行,甚至故意不执行?
评论后更新#1
我知道 a, b := GenericFunc()
不能引用 returned 值的类型。目前 Go 确实有“这取决于”情况是否需要来自用户输入的显式实例化。
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()
不行,因为这个
类型推断的当前规则是explicit。未考虑如何使用 return 值:
Type inference is based on
- a type parameter list
- a substitution map M initialized with the known type arguments, if any
- a (possibly empty) list of ordinary function arguments (in case of a function call only)
从 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)
}
如果您不能或不想事先确定切片的长度,您只能进行显式实例化。
此外,类型参数仍然无法通过 :=
shorthand 声明推断出来:
// what is m???
m, err := FromInterfaceSlice([]interface{}{1, 2, 3})