头图

译|There Are No Reference Types in Go

有一天,我用谷歌搜索一个 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 FamilyType Declaration
mapstruct { m *internalHashtable }
channelstruct { c *internalChannel }
slicestruct { 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 许可协议。转载请注明出处!


12 声望
5 粉丝
0 条评论
推荐阅读
如何快速定位现网 BUG
“幸福的家庭都是相似的,不幸的家庭却各有各的不幸”,托尔斯泰的名言。在 BUG 定位这件事情上,其实也有类似的现象:”菜鸟们的紧张无措都是相似的,老鸟们的方法却各有各的不同”。

有疑说阅读 916

封面图
Golang 中 []byte 与 string 转换
string 类型和 []byte 类型是我们编程时最常使用到的数据结构。本文将探讨两者之间的转换方式,通过分析它们之间的内在联系来拨开迷雾。

机器铃砍菜刀22阅读 55k评论 1

年度最佳【golang】map详解
这篇文章主要讲 map 的赋值、删除、查询、扩容的具体执行过程,仍然是从底层的角度展开。结合源码,看完本文一定会彻底明白 map 底层原理。

去去100214阅读 11k评论 2

年度最佳【golang】GMP调度详解
Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱, 虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻底的. 这篇文章将通过分析...

去去100213阅读 11.2k评论 4

【已结束】SegmentFault 思否技术征文丨浅谈 Go 语言框架
亲爱的开发者们:我们的 11 月技术征文如期而来,这次主题围绕 「 Go 」 语言,欢迎大家来参与分享~征文时间11 月 4 日 - 11 月 27 日 23:5911 月 28 日 18:00 前发布中奖名单参与条件新老思否作者均可参加征文...

SegmentFault思否11阅读 4.7k评论 11

封面图
【Go微服务】开发gRPC总共分三步
之前我也有写过RPC相关的文章:《 Go RPC入门指南:RPC的使用边界在哪里?如何实现跨语言调用?》,详细介绍了RPC是什么,使用边界在哪里?并且用Go和php举例,实现了跨语言调用。不了解RPC的同学建议先读这篇文...

王中阳Go8阅读 3.7k评论 6

封面图
【golang】sync.WaitGroup详解
上一期中,我们介绍了 sync.Once 如何保障 exactly once 语义,本期文章我们介绍 package sync 下的另一个工具类:sync.WaitGroup。

去去100213阅读 30.1k评论 2

12 声望
5 粉丝
宣传栏