为了账号安全,请及时绑定邮箱和手机立即绑定

为什么接收器在 Go 中按值传递?

为什么接收器在 Go 中按值传递?

Go
小唯快跑啊 2021-06-04 02:07:07
似乎你总是想要这个:func (self *Widget) Do() {}而不是这个func (self Widget) Do() {}如果是这样,那么获得前一种语义的方法应该是使用后一种语法。即接收者应该通过引用传递。
查看完整描述

3 回答

?
红糖糍粑

TA贡献1815条经验 获得超6个赞

这是因为Go 中的一切都是按值传递的。这使它与其他 C 系列语言保持一致,并且意味着您永远不需要记住您正在查看的情况是否是按值传递的。

从该链接:

与 C 系列中的所有语言一样,Go 中的所有内容都是按值传递的。也就是说,一个函数总是得到一个被传递的东西的副本,就好像有一个赋值语句给参数赋值一样。例如,将 int 值传递给函数会生成 int 的副本,而传递指针值会生成指针的副本,但不会生成指针指向的数据的副本。(有关这如何影响方法接收器的讨论,请参阅下一节。)

后来:

  func (s *MyStruct) pointerMethod() { } // method on pointer
  func (s MyStruct)  valueMethod()   { } // method on value

对于不习惯指针的程序员来说,这两个例子之间的区别可能会令人困惑,但情况其实很简单。在类型上定义方法时,接收者(s在上面的示例中)的行为就像它是方法的参数一样。将接收者定义为值还是指针是同一个问题,然后,函数参数应该是值还是指针。有几个考虑。

首先,也是最重要的,该方法是否需要修改接收器?如果是,则接收者必须是一个指针。(切片和映射充当引用,所以它们的故事有点微妙,但是例如要更改方法中切片的长度,接收者仍然必须是指针。)在上面的示例中,如果 pointerMethod 修改了s,调用者将看到这些更改,但 valueMethod 是使用调用者参数的副本(这是传递值的定义)调用的,因此调用者将看不到它所做的更改。

顺便说一下,指针接收器与 Java 中的情况相同,尽管在 Java 中指针隐藏在幕后;Go 的价值接收者是不寻常的。

二是对效率的考虑。如果接收器很大,例如一个大的结构,使用指针接收器会便宜得多。

接下来是一致性。如果该类型的某些方法必须有指针接收器,其余的也应该如此,因此无论如何使用该类型,方法集都是一致的。有关详细信息,请参阅方法集部分。

对于诸如基本类型、切片和小型结构之类的类型,值接收器非常便宜,因此除非方法的语义需要指针,否则值接收器是高效且清晰的。


查看完整回答
反对 回复 2021-06-28
?
jeck猫

TA贡献1909条经验 获得超7个赞

有时候,你不想要引用虽然通过。的语义


func (self Widget) Get() Value {

}

例如,如果您有一个小的不可变对象,则可能很有用。调用者可以肯定地知道这个方法不会修改它的接收者。如果接收者是一个指针而不先阅读代码,他们就无法知道这一点。


例如,对此进行扩展


// accessor for things Config

func (self Thing) GetConfig() *Config {

}

通过查看这个方法,我可以知道 GetConfig 总是会返回相同的 Config。我可以修改该配置,但我无法修改 Thing 中指向 Config 的指针。它非常接近 Thing 内部的 const 指针。


查看完整回答
反对 回复 2021-06-28
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

似乎你总是想要这个:

不。值接收器更通用。它可以用在所有指针接收器可以使用的地方;但是指针接收器不能用在值接收器可以使用的所有地方——例如,如果你有一个类型的右值表达式Widget;您可以对其调用值接收器方法,但不能调用指针接收器方法。


查看完整回答
反对 回复 2021-06-28
  • 3 回答
  • 0 关注
  • 212 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信