好像你总是想要这个:
func (self *Widget) Do() {
}
Run Code Online (Sandbox Code Playgroud)
而不是这个
func (self Widget) Do() {
}
Run Code Online (Sandbox Code Playgroud)
如果是这样,那么通过使用后一种语法来获得前一种语义OUGHT的方法.即接收者应该通过引用传递.
Tim*_*nes 27
这是因为Go中的所有内容都是按值传递的.这使得它与其他C族语言保持一致,并且意味着您永远不需要记住您正在查看的情况是否通过值传递.
从该链接:
与C系列中的所有语言一样,Go中的所有内容都按值传递.也就是说,函数总是获取正在传递的东西的副本,就好像有一个赋值语句将值赋给参数.例如,将int值传递给函数会生成int的副本,并且传递指针值会生成指针的副本,但不会生成它指向的数据.(有关如何影响方法接收器的讨论,请参阅下一节.)
然后呢:
Run Code Online (Sandbox Code Playgroud)func (s *MyStruct) pointerMethod() { } // method on pointer func (s MyStruct) valueMethod() { } // method on value
对于不习惯指针的程序员来说,这两个例子之间的区别可能令人困惑,但实际情况非常简单.在类型上定义方法时,接收器(
s
在上面的示例中)的行为就像它是方法的参数一样.然后,将函数参数定义为值还是指针,将接收器定义为值还是指针都是同一个问题.有几个注意事项.首先,最重要的是,该方法是否需要修改接收器?如果是,接收器必须是指针.(切片和贴图充当引用,因此它们的故事更加微妙,但是例如在接收方必须仍然是指针的方法中更改切片的长度.)在上面的示例中,如果pointerMethod修改了字段
s
,调用者将看到这些更改,但是使用调用者参数的副本调用valueMethod(这是传递值的定义),因此调用者所做的更改将对调用者不可见.顺便说一句,指针接收器与Java中的情况相同,尽管在Java中,指针隐藏在封面下; Go的价值接收器是不寻常的.
其次是效率的考虑.如果接收器很大,例如一个大的结构,使用指针接收器会便宜得多.
接下来是一致性.如果该类型的某些方法必须具有指针接收器,则其余方法也应如此,因此无论使用何种类型,方法集都是一致的.有关详细信息,请参阅方法集部分.
对于诸如基本类型,切片和小结构之类的类型,值接收器非常便宜,因此除非方法的语义需要指针,否则值接收器是高效且清晰的.
有时候,你不想要引用虽然通过.的语义
func (self Widget) Get() Value {
}
Run Code Online (Sandbox Code Playgroud)
例如,如果您有一个小的不可变对象,则可能很有用.调用者可以确定该方法不会修改它的接收者.如果接收器是一个没有先读取代码的指针,他们就无法知道这一点.
例如,扩展它
// accessor for things Config
func (self Thing) GetConfig() *Config {
}
Run Code Online (Sandbox Code Playgroud)
通过查看这个方法,我可以知道GetConfig总是会返回相同的Config.我可以修改该配置,但我无法在Thing中修改指向Config的指针.它非常接近Thing内部的const指针.