修改错别字
相关信息:
- 类型:文档文章
- 文章: 关于 Go 泛型 (Generics)
- 文档: 《Go Blog 中文翻译()》
此投稿已在 4年前 合并。
内容修改:
Old | New | Differences |
---|---|---|
1 | ||
2 | 1 | Ian Lance Taylor |
3 | 2 | 2019 年 7 月 31 日 |
4 | 3 | … | … |
77 | 76 | 在动态类型的语言之中,比如 Python 或者 JavaScript,你不需要费心指明变量类型,直接写函数就可以了。在 Go 之中一样的套路可不行,因为 Go 是静态类型的语言,要求你明确写出切片和切片元素的类型。 |
78 | 77 | |
79 | 78 | 大多其他静态类型的语言,比如 C++ 或者 Java、Rust、Swift,都支持使用泛型来面对这种类型处理问题。 |
80 | ||
79 | ||
81 | 80 | |
82 | 81 | #### Go 范型编程在当下 |
83 | 82 | … | … |
87 | 86 | |
88 | 87 | 换句话说,Go 语言之中的接口类型是范型编程的一种形式。接口让我们能够在捕捉不同类型之间的相似性之后,用方法来描述这种相似性。我们可以写对接口类型作用的函数,这些函数将会对实现了指定方法的所有类型生效。 |
89 | 88 | |
90 | 但是这样的手段远远达不到我们想要的程度。用上接口,你还是得自己手动加上各种联系类型的方法。只是为了把一个切片颠倒一下,就定义一种类型感觉上还是有点膈应。而且你给不同类型的切片写的方法还都是一 | |
89 | 但是这样的手段远远达不到我们想要的程度。用上接口,你还是得自己手动加上各种联系类型的方法。只是为了把一个切片颠倒一下,就定义一种类型感觉上还是有点膈应。而且你给不同类型的切片写的方法还都是一模一样的。所以这样我们不过是把重复的代码整合压缩到了一起,并没将其消除。虽说接口是范型的一种形式,但是它并没有满足范型能给我们的全部。 | |
91 | 90 | |
92 | 91 | 另一种不同的、绕过自己写方法的需要的用接口实现范型策略,就是让语言本身为某些类型定义方法。在当下这还不是语言本身所支持的,但是,比如说语言本身可以定义任何一个切片都有一个返回一个元素的索引方法。但是为了在实践之中使用这样的方法,这个方法必须返回一个空接口类型,于是就失去了静态类型所带来的好处。更微妙的是,这样是无法定义接受两个元素类型相同的不同切片的函数的,亦或是接受某一种元素类型的 map 然后返回同样元素类型的切片的函数。Go 是静态类型的语言,因为静态类型会让大型程序的工作更加简单。我们是不愿意为了得到范型带来的好处而失去静态类型带来的优点的。 |
93 | 92 | … | … |
127 | 126 | - 调用一组函数,使用上下文,通过返回第一个函数的结果来结束操作。随后结束其他的 Goroutine 并做清理工作。 |
128 | 127 | |
129 | 128 | 我已经在实际中见过所有这些函数针对不同类型被写了很多遍。在 Go 里面写这些函数并不是很难。但是如果能重用一个被调试好的、高效、能对所有类型通用的实现会是一个很好的事情。 |
130 | ||
129 | ||
131 | 130 | 要澄清一下,这些只是例子。实际上有了泛型,有许多通用意义的函数是可以更加方便和安全地完成的。 |
132 | 131 | |
133 | 132 | 同时,如我早些写道的,泛型不仅仅可以用在函数上,还可以用在数据结构上。 | … | … |
151 | 150 | |
152 | 151 | 我希望我已经解释清楚为什么泛型是值得深入的。 |
153 | 152 | |
154 | ||
153 | ||
155 | 154 | |
156 | 155 | #### 收益和成本 |
157 | 156 | … | … |
230 | 229 | ``` |
231 | 230 | |
232 | 231 | 换句话说,虽然泛型的 `Reverse` 比 `ReverseInts` 和 `ReverseStrings` 稍微复杂些,但是这些复杂性由书写者处理,而不是调用者。 |
233 | ||
232 | ||
234 | 233 | |
235 | 234 | #### 契约 |
236 | 235 | … | … |
300 | 299 | |
301 | 300 | 你可能注意到了这个契约看起来有点像 `fmt.Stringer` 接口,所以需要指出的是,`ToStrings` 函数的参数并不是 `fmt.Stringer` 的切片,而是某种(确定了的)类型的切片,这种类型实现了 `fmt.Stringer`。具体类型的切片和 `fmt.Stringer` 的切片在内存表示上通常是不一样的,Go 也不支持两者之间的直接转换。所以即使 `fmt.Stringer` 已经存在,这个契约仍有写的必要。 |
302 | 301 | |
303 | ||
302 | ||
304 | 303 | |
305 | 304 | #### 对多个类型定契约 |
306 | 305 | … | … |
373 | 372 | } |
374 | 373 | ``` |
375 | 374 | |
376 | ||
375 | ||
377 | 376 | |
378 | 377 | #### 泛型数据结构 |
379 | 378 | … | … |
459 | 458 | 没错就该这样。泛型写起来会稍微复杂一些,因为被支持类型的类型参数往往是要显式地写出来。但是用起来和普通的非泛型数据结构就没什么区别。 |
460 | 459 | |
461 | 460 | |
462 | ||
461 | ||
463 | 462 | |
464 | 463 | #### 下一步 |
465 | 464 |