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

huangapple go评论118阅读模式
英文:

When should I define methods on values (instead of on pointers) in Go?

问题

定义了

type MyInt int

我想定义一个方法.ShowMe(),它只打印值。我可以使用*MyInt来定义这个方法:

func (this *MyInt) ShowMe() {
	fmt.Print(*this, "\n")
}

或者使用MyInt来定义:

func (this MyInt) ShowMe() {
	fmt.Print(this, "\n")
}

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

英文:

Having defined

type MyInt int

I would like to define a method .ShowMe() that just prints the value. I can define this either using *MyInt:

func (this *MyInt) ShowMe() {
	fmt.Print(*this, "\n")
}

Or using MyInt:

func (this MyInt) ShowMe() {
	fmt.Print(this, "\n")
}

In what cases is it recommended to define methods on values, instead of on pointers?

答案1

得分: 10

当做出这个决定时,有两个问题需要考虑:

  1. 我是否想要能够修改接收者的值?
  2. 复制接收者的值是否会很昂贵?

如果对这两个问题的回答都是肯定的,那么就在指针上定义该方法。

在你的例子中,你不需要修改接收者的值,而且复制接收者也不会很昂贵。

对于决定问题2的答案,我的经验法则是:如果接收者是一个具有多个字段的结构体,则传递指针。否则传递值。

英文:

There are two questions to ask yourself when making this decision:

  1. Do I want to be able to modify the receiver's value?
  2. Will copying the receiver's value be expensive?

If the answer to either of these questions is yes, then define the method on a pointer.

In your example, you don't need to modify the receiver's value and copying the receiver isn't expensive.

For deciding the answer to #2, my rule of thumb is: if the receiver is a struct with more than one field, pass by pointer. Otherwise pass by value.

答案2

得分: 7

Go FAQCC许可)有一个答案:

我应该在值上定义方法还是指针上定义方法?

func (s *MyStruct) pointerMethod() { } // 指针上的方法
func (s MyStruct)  valueMethod()   { } // 值上的方法

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

首先,也是最重要的,方法是否需要修改接收器?如果需要修改,接收器必须是指针。(切片和映射是引用类型,所以它们的情况稍微复杂一些,但是例如要在方法中更改切片的长度,接收器仍然必须是指针。)在上面的例子中,如果pointerMethod修改了s的字段,调用者将看到这些更改,但是valueMethod是使用调用者参数的副本调用的(这就是传递值的定义),所以它所做的更改对调用者是不可见的。

顺便说一下,指针接收器与Java中的情况完全相同,尽管在Java中指针是隐藏在底层的;而Go的值接收器才是不寻常的。

其次是效率的考虑。如果接收器很大,比如一个大的struct,使用指针接收器会更便宜。

接下来是一致性的考虑。如果类型的某些方法必须具有指针接收器,那么其余的方法也应该具有指针接收器,这样方法集在使用类型的方式上是一致的。有关详细信息,请参阅方法集部分

对于基本类型、切片和小的structs等类型,值接收器非常便宜,因此除非方法的语义要求指针,否则值接收器是高效和清晰的。

英文:

The Go FAQ (CC-licensed) has an answer:

> ### Should I define methods on values or pointers?
>
> func (s *MyStruct) pointerMethod() { } // method on pointer
> func (s MyStruct) valueMethod() { } // method on value
>
> For programmers unaccustomed to pointers, the distinction between
> these two examples can be confusing, but the situation is actually
> very simple. When defining a method on a type, the receiver (s in the
> above example) behaves exactly as if it were an argument to the
> method. Whether to define the receiver as a value or as a pointer is
> the same question, then, as whether a function argument should be a
> value or a pointer. There are several considerations.
>
> First, and most important, does the method need to modify the
> receiver? If it does, the receiver must be a pointer. (Slices and
> maps are reference types, so their story is a little more subtle, but
> for instance to change the length of a slice in a method the receiver
> must still be a pointer.) In the examples above, if pointerMethod
> modifies the fields of s, the caller will see those changes, but
> valueMethod is called with a copy of the caller's argument (that's
> the definition of passing a value), so changes it makes will be
> invisible to the caller.
>
> By the way, pointer receivers are identical to the situation in Java,
> although in Java the pointers are hidden under the covers; it's Go's
> value receivers that are unusual.
>
> Second is the consideration of efficiency. If the receiver is large, a
> big struct for instance, it will be much cheaper to use a pointer
> receiver.
>
> Next is consistency. If some of the methods of the type must have
> pointer receivers, the rest should too, so the method set is
> consistent regardless of how the type is used. See the section on
> method sets

> for details.
>
> For types such as basic types, slices, and small structs, a value
> receiver is very cheap so unless the semantics of the method requires
> a pointer, a value receiver is efficient and clear.

huangapple
  • 本文由 发表于 2011年6月13日 17:56:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/6328943.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定