以下代码在Go中实现了一个int列表:
package main
import "fmt"
type List struct {
Head int
Tail *List
}
func tail(list List) *List {
return list.Tail
}
func main() {
list := List{Head: 1, Tail:
&List{Head: 2, Tail:
&List{Head: 3, Tail:
nil}}}
fmt.Println(tail(list).Head)
}
问题是这仅适用于int
。如果我想要一个strings
列表,我需要再次重新实现每个列表方法(例如tail
)!这显然不实用,所以,这可以通过使用空接口解决:
type List struct {
Head interface{} // Now works for any type!
Tail *List
}
问题是,1。由于类型转换,这似乎要慢得多,2。它抛弃了类型安全,允许人们键入检查任何东西:
// This type-checks!
func main() {
list := List{Head: 123456789 , Tail:
&List{Head: "covfefe" , Tail:
&List{Head: nil , Tail:
&List{Head: []int{1,2}, Tail:
nil}}}}
fmt.Println(tail(list).Head)
显然,该程序应不以静态类型语言进行类型检查。
如何实现一个List类型,它不需要我为每个包含的类型重新实现所有List方法,但是它能保持预期的类型安全性和性能?
答案 0 :(得分:7)
Go doesn't have generic types,所以你坚持使用你列出的选项。遗憾。
同时,Go的内置映射和切片,以及使用空接口构造容器(具有显式拆箱)的能力意味着在许多情况下,可以编写执行泛型将启用的代码(如果不太顺利)。
如果您对要存储在容器中的元素有更多了解,可以使用更专业的接口类型(而不是空接口interface{}
),
但那是关于它的。请在此处查看此示例:Why are interfaces needed in Golang?
另外,如果你错过了它,标准库已经在container/list
包中有一个双向链表实现(对于值也使用interface{}
类型)。
答案 1 :(得分:4)
确认我们希望通用类型更慢,而不是更快,这一点非常重要。优秀的fastutil Java库通过使用具体实现,优于标准库中更灵活的类。
Russ Cox(Go的作者之一)summarises the situation是这样的:
- (C方法。)将它们排除在外。
- 这会减慢程序员的速度。
- (C ++方法。)编译时专业化或宏扩展。
- 这会减慢编译速度。
- (Java方法。)隐含地包装所有内容。
- 这会减慢执行速度。
您可能对this living document感兴趣,其中列出了许多优点和缺点。
正如另一个答案所指出的,Go并不支持您在此尝试实现的设计。就个人而言,我只是复制代码 - 它并不多,测试很便宜,大多数时候你实际上并不需要你想要实现的通用行为。
答案 2 :(得分:1)
如@Output
提到的那样,没有一种直截了当的方式。
您可以尝试使用code generation为新类型生成方法。