在Go中传递指针与值

ymg*_*ymg 4 pointers go

我读过这篇与Go完全无关的有趣博客文章,作者说过的一件事引起了我的注意,以下引用:

...例如,将通道作为函数all的参数传递是有效的,因为Go中的通道与指向C中实现的通道数据结构的指针一样简单.对于地图和其他一些通道是相同的类型.但传递数组或结构是低效的; 相反,我们应该将指针传递给这些类型.

使用Go内部类型或结构时,为什么传递指针效率不高?

Sea*_*ean 12

上下文与此相关:

然而,Go的类型系统是如此复​​杂; 程序员需要知道标准类型实现的所有细节,才能正确使用它们.例如,它是有效的......

作者说地图和频道看起来像值,但在复制时就像指针一样.

对于其他数据类型,参数中有一个参数*,这是一个可以在适当位置修改的明确信号.通常,论证也有一个&前置,这是论证被修改的另一个信号.

传递地图和通道时,那些语法信号不存在.这会导致像这样的意外结果:

http://play.golang.org/p/lS1FXZnxb8

类似的批评也可以应用于数组之间的巨大差异,例如[256]byte,像[]byte缺少大小是不同复制行为的唯一信号.

所有这一切都放在一边,作者错误地等同于复制低效率.确实,复制有时需要比传递指针更多的CPU周期或内存访问.然而,情况并非总是如此.它取决于结构的大小和编译器执行的优化.

复制(即传递值)与传递指针的决定也与该函数是否可以修改该参数有关.

对于不打算由函数修改的小型结构和数组,请按值传递它们.这消除了由于意外修改而导致的整个类错误,甚至比const其他语言更好,因为没有办法欺骗和绕过它.当然,总是要小心嵌入式指针,包括地图和切片,因为这些指针仍然可以在函数内修改.


Mat*_*att 5

传递指针并不低效.但是作者是正确的:因为默认情况下数组和结构是按值传递的,所以它们的内容被复制到每个新的函数调用中.这可能是低效的.

根据Go切片:usage和internals,数组按值传递.(切片使用指向引擎盖下阵列的指针,因此传递效率更高.)

与切片一样,通道由make(至少隐含地)分配,因此通道充当对实际数据结构的引用.

因此,当您使用结构体和实际数组时,通常会传递它们的引用.(请参阅Sean的答案,了解更多有关此问题的详细信息.他指出复制并不总是效率低下.有时这是可取的.)