我读过这篇与Go完全无关的有趣blog post,作者所说的一件事引起了我的注意,以下引用:
...例如,将通道作为函数all的参数传递是有效的,因为Go中的通道与指向C中实现的通道数据结构的指针一样简单。对于map来说它是相同的和其他一些类型。但传递数组或结构是低效的;相反,我们应该将指针传递给这些类型。
为什么在使用Go内部类型或结构时传递指针效率不高?
答案 0 :(得分:12)
上下文与此相关:
然而,Go的类型系统是如此复杂;程序员需要知道 之前有关标准类型实施的所有细节 他们可以正确使用它们。例如,它很有效......
作者说地图和频道看起来像是值,但在复制时就像指针一样。
对于其他数据类型,参数中包含*
,这是一个明确的信号,可以在适当的位置进行修改。通常,参数前面也有&
,这是参数被修改的另一个信号。
传递地图和频道时,那些句法信号不存在。这会产生意想不到的结果:
http://play.golang.org/p/lS1FXZnxb8
类似的批评可以应用于像[256]byte
这样的数组和像[]byte
这样的切片之间的巨大差异,其中缺少大小是不同复制行为的唯一信号。
所有这一切都放在一边,作者错误地将复制和效率低下等同起来。确实,复制有时需要比传递指针更多的CPU周期或内存访问。然而,情况并非总是如此。它取决于结构的大小和编译器执行的优化。
复制(即传递值)与传递指针的决定也与该函数是否可以修改该参数有关。
对于不打算由函数修改的小型结构和数组,按值传递。这消除了因意外修改而导致的整类错误,甚至比其他语言中使用的const
更好,因为没有办法欺骗和绕过它。当然,总是要小心嵌入式指针,包括地图和切片,因为这些指针仍然可以在函数内修改。
答案 1 :(得分:5)
传递指针并不低效。但是作者是正确的:因为默认情况下数组和结构是按值传递的,所以它们的内容被复制到每个新的函数调用中。这可能效率低下。
根据Go slices: usage and internals,数组按值传递。 (切片使用指向引擎盖下阵列的指针,因此传递效率更高。)
与切片类似,渠道由make
(至少是隐式)分配,因此channels act as a reference to the actual data structure。
因此,当您使用结构体和实际数组时,通常会传递它们的引用。 (请参阅Sean的答案,了解更多有关此问题的详细信息。他指出,复制并非总是效率低下。有时它是可取的。)