通过引用或价值

时间:2014-08-17 21:32:17

标签: go

如果我有以下结构的实例

type Node struct {
    id          string 
    name        string  
    address     string
    conn        net.Conn
    enc         json.Encoder
    dec         json.Decoder
    in          chan *Command
    out         chan *Command
    clients     map[string]ClientNodesContainer
}

我无法理解何时应该通过引用发送结构,何时应该按值发送它(考虑到我不想对该实例进行任何更改),是否有一个经验法则可以使它更容易决定?

所有我能找到的是当它的小或便宜复制时按值发送一个结构,但是小的真的意味着小于64位地址吗?

如果有人可以指出一些更明显的规则,

会很高兴

3 个答案:

答案 0 :(得分:10)

规则很简单:

  

没有概念"通过引用传递/发送"在Go中,你所能做的只是传递价值。

关于是否传递结构的值或指向结构的指针的问题(这不是通过引用调用的!):

  1. 如果要修改函数或方法中的值:传递指针。
  2. 如果您不想修改该值:
    1. 如果您的结构:使用指针。
    2. 否则:这没关系。
  3. 所有这些都在考虑复制费用是多少浪费时间。副本很便宜,即使是中型结构也是如此。在分析后,传递指针可能是一个合适的优化

    你的结构不大。大型结构包含wholeWorldBuf [1000000]uint64等字段。 像你这样的微小结构可能会或可能不会从传递指针中获益,而任何提供更好的建议的人都在说谎:这完全取决于你的代码和通话模式。

    如果你没有合理的选项和分析显示复制你的结构花费时间:尝试使用指针。

答案 1 :(得分:2)

&#34>的原则通常会传递你不打算变异的小结构的值。我同意,但是这个结构现在在x64上是688字节,大多数是嵌入式json结构中的结构。细分是:

  • 16 * 4 = 64为三个字符串(指针/ len对)和net.Conn(接口值)
  • 208用于嵌入式json.Encoder
  • 392 for embedded json.Decoder
  • 8 * 3 = 24为三个chan / map值(必须是指针)

Here's我以前使用的代码,虽然您需要在本地保存它以运行它,因为它使用unsafe.Sizeof

您可以嵌入*Encoder / *Decoder而不是指针,只需104字节。不过,我认为保持现状并通过*Node是合理的。

接收器类型上的转到code review comments说"有多大?假设它相当于将所有元素作为参数传递给方法。如果感觉太大,对接收器来说也太大了。"这里有不同意见的空间,但对我来说,九个值,一些多个单词,"感觉很大"甚至在获得精确数字之前。

"Pass Values" section审核评论文档中说"此建议不适用于大型结构,甚至可能适用于可能增长的小结构。"它没有说"大"相同的标准。适用于接收器的正常参数,但我认为这是一种合理的方法。

在代码审查文档中提到的确定大小的部分细节是,Go中的许多内容都是内部指针或包含引用的小结构:切片(但不是固定大小的数组),字符串,{{ 1}}值,函数值,通道,映射。你的struct可能拥有一个指向64KB缓冲区的interface,或者通过[]byte拥有一个大结构,但复制起来仍然很便宜。我在另一个答案中wrote some about this,但我在那里所说的一切都无法阻止人们做出一些不那么科学的判断。

看看标准库方法的作用很有意思。 bytes.Replace有十个单词'值得args,所以至少有时可以复制到堆栈上。另一方面,go/ast倾向于传递引用(interface指针或接口值),即使对于非巨大结构上的非变异方法也是如此。结论:很难将它简化为几个简单的规则。 :)

答案 2 :(得分:-1)

大多数时候你应该使用传递参考。像:

func (n *Node) exampleFunc() {
    ...
}

只有当您希望使用按值传递实例时,才能确保您的实例不会发生更改。