猿问

Go 中的泛型是什么?

最近有很多关于 Go 的批评,因为它不支持泛型。这到底是什么意思呢?您如何向来自像 Ruby 这样的动态类型语言的人解释这一点,而这不是一个熟悉的概念?


尚方宝剑之说
浏览 298回答 2
2回答

缥缈止盈

William B. Yager 的 博客文章提醒了为什么 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}) 所以这就是为什么,如果你想保留类型系统的好处,你必须使用一些代码生成,为你的特定类型生成样板代码。该gen项目是这种方法的一个例子:gen在开发时使用命令行为您的类型生成代码。gen不是进口;生成的源代码成为您项目的一部分,并且不需要任何外部依赖项。2017 年 6 月更新:Dave Cheney 在他的文章“ Simplicity Debt ”和“ Simplicity Debt Redux ”中详细说明了 Go 泛型的含义。由于Go 2.0 现在在核心团队层面被积极讨论,Dave 指出泛型涉及到什么,那就是:错误处理:泛型将允许monadic 错误处理,这意味着您需要在其余部分之上了解 monad:启用处理计算管道而不是在每次函数调用后检查错误。但是:你需要了解 monad!集合:促进自定义集合类型,无需接口装箱和类型断言。{}但这留下了如何处理内置切片和地图类型的问题。切片:它是否会消失,如果是这样,这将如何影响诸如处理调用结果之类的常见操作io.Reader.Read?如果切片没有消失,是否需要添加运算符重载,以便用户定义的集合类型可以实现切片运算符?Vector:Go 的类似 Pascal 的数组类型具有在编译时已知的固定大小。如何在不诉诸不安全黑客的情况下实现可增长的向量?迭代器:你真正想要做的是在数据库结果和网络请求上组合迭代器。简而言之,来自流程外部的数据——当数据位于流程之外时,检索它可能会失败。在这种情况下,您有一个选择,您的Iterable接口是否返回一个值、一个值和一个错误,或者您可能沿着选项类型路线走下去。不变性:将函数参数标记为的能力const是不够的,因为虽然它限制了接收者改变值,但它并没有禁止调用者这样做,这是我今天在 Go 程序中看到的大多数数据竞争。也许 Go 需要的不是不变性,而是所有权语义。正如Russ Cox在“我的 2017 年 Go 决议”中所写:今天,也有更新的尝试可以学习,包括 Dart、Midori、Rust 和 Swift。最新的讨论是Go 问题 15292:它还引用了“ Go 泛型讨论摘要”。
随时随地看视频慕课网APP

相关分类

Go
我要回答