有一天,我用谷歌搜寻一个 Go 问题,谷歌将我疏导到 Go FAQ 页面。问题解决后,我浏览了整个 FAQ。
这是一次很棒的浏览,我从文章中学到了很多。但我留神到一个问题,为什么数组是值, 而 map、slice 和 channel 是援用?回答如下:
此话题历史长远。在晚期,map 和 channel 都是语法指针,不能申明和应用非指针实例。此外,咱们在全力以赴摸索数组如何工作。最终,咱们认为指针和值的严格拆散使语言更难应用。将这些类型更改为对关联的共享数据结构的援用,就解决了这些问题。扭转给语言减少了一些令人遗憾的复杂性,但却对可用性产生了很大的影响:Go 一经推出,就成为了一种更高效、更难受的语言。
令我诧异的是,Go 官网文档仍在应用“援用类型”的概念,因为自 2013 年 4 月 3 日以来,“援用类型”的概念已从 Go 标准中齐全删除。当初 Go 标准中有 10 个“援用”词,没有一个代表“援用类型”的概念。
另一个惊喜是这句话:
… 指针和值的严格拆散使该语言更难应用。…
此回答将指针和值视为两个不兼容的概念。然而,Go 标准将指针视为非凡值,指针被称为“指针值”。值只是类型的实例。显然,Go 标准中“指针”一词的定义很好。我认为如果应用“指针值和非指针值”会更好。
所以,我认为此回答给 Go 社区带来了很多困惑。它与以后 Go 标准抵触,并且突破了概念的一致性。
谈回第一个惊喜,我认为称说 map/slice/channel 值为援用值齐全没有必要。不仅因为“reference”这个词在编程世界中被滥用了,还因为 map/slice/channel 值只是一般的正常值
以下是 map/slice/channel 类型的外部申明:
Type Family | Type Declaration |
---|---|
map | struct {m *internalHashtable} |
channel | struct {c *internalChannel} |
slice | struct {array *internalArray; len int; cap int} |
请留神,下面的申明可能不齐全与官网或非官方的 Go 实现中的申明雷同。Go 实现能够间接应用指针示意 map 和 channel 的值,但 Go 标准 / 编译器永远不会将它们视为指针。因而,你能够释怀的将 map/slice/channel 类型视为下面申明的指针包装类型,而不会有任何问题。
从下面的申明,很容易得出结论:map/slice/channel 只是蕴含一个非导出指针字段的构造类型。将它们称为援用类型是齐全没有必要的。
Map 和 slice 类型与个别构造类型的确有一个区别。与个别构造类型不同,对于 map 或 slice 类型 T,T{} 不是 T 的零值。但这不是将 map 或 slice 类型拆分为新的援用类型类别的好理由。
通过了解 Go 的以下两个规定:
- map/slice/channel 值只是一般的指针包装构造的值
- 所有赋值,包含参数传递等,都是浅值复制(指针指向的值不会被复制)
Gopher 应该分明地了解赋值中的 dest 和 source map/slice/channel 值将共享被包装的指针所指向的同一底层数据。
概念是用来帮忙程序员了解语言的机制,而不是混同他们。值、指针值和非指针值的概念足以让 Gopher 了解 Go。
我心愿 Go 文档不会毁坏概念定义的一致性。
本文作者 :cyningsun
本文地址 :https://www.cyningsun.com/08-…
版权申明:本博客所有文章除特地申明外,均采纳 CC BY-NC-ND 3.0 CN 许可协定。转载请注明出处!