最近有很多关于Golang的批评,因为它不支持泛型。这到底是什么意思呢?您如何向来自像Ruby这样的动态类型语言的人解释这一点,这不是一个熟悉的概念?
答案 0 :(得分:6)
在动态类型语言中,您不关心它是什么类型的列表,只是它是一个列表。但是,在静态类型语言中,您确实关心它是什么类型的列表,因为类型是“A的列表”,其中“A”是某种类型。也就是说,list A
与list B
的类型不同。
因此,当您谈到泛型时,使用A -> B
调用列表中foreach
类型的某个函数意味着该列表必须是list A
。但是......如果你使用泛型,那么你不必声明A
是什么,你可以在以后填写它。因此,您建立了一个合同,其中给定list C
和函数A -> B
,A === C
以便编译。这大大减少了样板。
在Go中,由于缺乏泛型和声明这种类型合同的能力,你必须编写一个函数,该函数在int列表,double列表,字符串列表等上运行。你可以'只是以“通用”的方式定义事物。
答案 1 :(得分:2)
William B. Yager blog post提醒为什么Go中存在的“通用”部分是不够的:
您可以轻松编写通用功能 假设您想编写一个函数,该函数为可以进行哈希处理的对象打印哈希码。您可以定义一个允许您使用静态类型安全保证执行此操作的接口,如下所示:
type Hashable interface {
Hash() []byte
}
func printHash(item Hashable) {
fmt.Println(item.Hash())
}
现在,您可以向
Hashable
提供任何printHash
对象,并且您还可以获得静态类型检查。这很好。如果您想编写通用数据结构怎么办? 让我们写一个简单的链表。在Go中编写通用数据结构的惯用方法是:
(这只是一个开始)
type LinkedList struct {
value interface{}
next *LinkedList
}
func (oldNode *LinkedList) prepend(value interface{}) *LinkedList {
return &LinkedList{value, oldNode}
}
在Go中构建通用数据结构的“正确”方法是将内容转换为顶级类型,然后将它们放入数据结构中。这就是Java过去常常工作的方式,大约在2004年。然后人们意识到这完全打败了类型系统的目的。
如果您拥有这样的数据结构,则可以完全消除类型系统提供的任何好处。例如,这是完全有效的代码:
node := tail(5).prepend("Hello").prepend([]byte{1,2,3,4})
这就是为什么,如果你想保留类型系统的好处,你必须使用一些代码生成来生成特定类型的boileplate代码。
gen
project 就是这种做法的一个例子:
gen
在开发时使用命令行为您的类型生成代码gen
不是导入;生成的源成为项目的一部分,不需要外部依赖。
2017年6月更新:Dave Cheney详细介绍了Generics for Go在他的文章“Simplicity Debt”和“Simplicity Debt Redux”中的含义。
自Go 2.0 is now actively discussed at the core team level以来,Dave指出了泛型所涉及的内容,即:
io.Reader.Read
的结果?
如果切片没有消失,是否需要添加运算符重载,以便用户定义的集合类型可以实现切片运算符?Iterable
接口是否返回值,值和错误,或者您可以选择类型路径。const
的能力不足,因为虽然它限制接收者改变值,但它并不禁止调用者这样做,是我今天在Go节目中看到的大部分数据竞赛
也许Go需要的不是不变性,而是所有权语义。由于Russ Cox在“My Go Resolutions for 2017”中写道:
今天,还有更新的尝试,包括Dart,Midori,Rust和Swift。
最新讨论是Go issue 15292:它还引用了“Summary of Go Generics Discussions”。