您在这里try 做的事情表明您期望GO的泛型是类型擦除的(就像Java泛型一样).然而,它们并非如此.
你有一个List[int]
,这意味着它的Add
方法如下所示:
func (l *List) Add(el int) {
l.Elements = append(l.Elements, el)
}
然后,try 将此代码添加到实现该接口的一组对象中:
Add(v any)
现在,你可能认为int
可以用作any
,你是对的,它可以,但当你看到:
var s []ListInterface[any]
您的意思是说,所述片中的所有元素都将有一个接受any
类型参数的Add
方法,因此这意味着:
s[0].Add("foo")
s[1].Add(123)
应该总是有效的电话.如果s[0]
的类型是List[int]
,就像你的代码片段中的情况一样,这不成立.你将try 向Elements
追加一个类型为[]int
的字符串.
有一种说法认为,应该允许相反的情况:
s := []ListInterface[int]{}
s = append(s, &List[any]{})
Seed as List[any]
将接受int
参数,但这也是不允许的.在某些情况下,这可能是有用的,但在许多情况下,这可能是有问题的.
本质上,Go中的泛型是在编译时处理的东西.当您创建一个List[int]
时,编译器将创建一个类似List_int
的类型,并在该类型上实现Add(el int)
方法,就像它将对您最终使用的任何其他List
类型一样.除非您创建List[any]
,否则这些类型都不会有Add(any)
方法.可以将其视为编译器辅助的模板代码生成.不是运行时类型擦除.
结果是:List[int]
和List[any]
是完全不同的类型,因此不能在一个切片中并排坐在一起,就像它们是同一类型一样.如果你想做你想做的事情,你可以这样做:
func (l *List[T]) AddAny(v any) {
tv, ok := v.(T)
if !ok {
return // or return an error
}
l.Add(tv)
}
接受any
值的方法,使用类型断言查看给定值是否与列表的基础类型兼容,如果是,则添加该值.然后,您可以将它们添加到如下所示的单个切片中:
type Lists interface {
AddAny(any)
}
s := []Lists{}
s = append(s, &List[int]{}, &List[string]{})
s[0].AddAny(123) // will work
s[0].AddAny("foo") // will not, with the current code this will silently fail
s[1].AddAny("foo") // works fine
s[1].AddAny(123) // silently fails
但实际上,当您做这样的事情时,代码只是尖叫着X-Y问题,其中您试图使用Y(泛型)来解决问题,而真正的问题是X:解决问题的最佳方法是什么?