英文:
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
当做出这个决定时,有两个问题需要考虑:
- 我是否想要能够修改接收者的值?
- 复制接收者的值是否会很昂贵?
如果对这两个问题的回答都是肯定的,那么就在指针上定义该方法。
在你的例子中,你不需要修改接收者的值,而且复制接收者也不会很昂贵。
对于决定问题2的答案,我的经验法则是:如果接收者是一个具有多个字段的结构体,则传递指针。否则传递值。
英文:
There are two questions to ask yourself when making this decision:
- Do I want to be able to modify the receiver's value?
- 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
我应该在值上定义方法还是指针上定义方法?
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论