什么时候应该在Go中定义值(而不是指针)的方法?

9 go

定义了

type MyInt int
Run Code Online (Sandbox Code Playgroud)

我想定义一个.ShowMe()只打印值的方法.我可以使用*MyInt以下方法定义:

func (this *MyInt) ShowMe() {
    fmt.Print(*this, "\n")
}
Run Code Online (Sandbox Code Playgroud)

或使用MyInt:

func (this MyInt) ShowMe() {
    fmt.Print(this, "\n")
}
Run Code Online (Sandbox Code Playgroud)

在什么情况下建议定义值的方法,而不是指针?

Eva*_*haw 9

做出这个决定时,有两个问题要问自己:

  1. 我是否希望能够修改接收器的值?
  2. 将复制接收者的价值变得昂贵吗?

如果这些问题中的任何一个的答案都是肯定的,那么在指针上定义方法.

在您的示例中,您不需要修改接收器的值,并且复制接收器并不昂贵.

为了确定#2的答案,我的经验法则是:如果接收器是具有多个字段的结构,则通过指针传递.否则按值传递.


小智 5

转到FAQ(CC许可)有一个答案:

我应该在值或指针上定义方法吗?

func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct)  valueMethod()   { } // method on value
Run Code Online (Sandbox Code Playgroud)

对于不习惯指针的程序员来说,这两个例子之间的区别可能令人困惑,但实际情况非常简单.在类型上定义方法时,接收器(上例中的s)的行为就像它是方法的参数一样.然后,将函数参数定义为值还是指针,将接收器定义为值还是指针都是同一个问题.有几个注意事项.

首先,最重要的是,该方法是否需要修改接收器?如果是,接收器必须是指针.(切片和贴图是引用类型,因此它们的故事更加微妙,但是例如在方法中更改切片的长度,接收器必须仍然是指针.)在上面的示例中,如果pointerMethod 修改s的字段,调用者将看到这些更改,但是 valueMethod使用调用者参数的副本调用(这是传递值的定义),因此调用者所做的更改将对调用者不可见.

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

其次是效率的考虑.如果接收器很大,struct例如,使用指针接收器便宜得多.

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

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