为什么接收者在Go中通过价值传递? [英] Why are receivers pass by value in Go?

查看:87
本文介绍了为什么接收者在Go中通过价值传递?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


$ b

  func(self * Widget)Do(){
}

不是这个

  func(self Widget)Do(){
}

如果是这样,那么通过使用后一种语法来获得以前的语义 OUGHT 的方式。即接收者应该通过引用传递。

解决方案

这是因为 Go中的所有内容都是按值传递的。这使得它与其他C族语言一致,并且意味着你永远不需要记住你正在看的情况是否通过价值。



从那个link:


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


然后:


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

对于不习惯指针的程序员来说,这两个例子之间的区别可以混乱,但情况其实很简单。当在一个类型上定义一个方法时,接收者(上面例子中的 s )的行为就好像它是方法的参数一样。无论是将接收器定义为值还是指针都是同一个问题,那么函数参数应该是值还是指针。有几个考虑因素。

首先,最重要的是,该方法是否需要修改接收器?如果是这样,接收器必须是一个指针。 (切片和贴图作为参考,所以它们的故事更加微妙,但是例如改变方法中切片的长度,接收器必须仍然是一个指针。)在上面的例子中,如果pointerMethod修改了字段 s ,调用者将会看到这些改变,但是valueMethod被调用者参数的副本调用(这是传递一个值的定义),所以它所做的改变将不可见给指定者。



顺便提一下,指针接收器与Java中的情况相同,但在Java中,指针隐藏在封面之下;这是Go的价值接受者是不寻常的。其次是对效率的考虑。如果接收器很大,例如一个大结构,使用指针接收器会便宜得多。

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



对于基本类型,切片和小结构等类型,值接收器非常便宜,因此除非方法的语义需要一个指针,价值接收者是高效和清晰的。



Seems like you'd ALWAYS want this:

func (self *Widget) Do() {
}

instead of this

func (self Widget) Do() {
}

If so, then the way to get the former semantics OUGHT to be by using the latter syntax. i.e. receivers ought to be pass by reference.

解决方案

It is because everything in Go is pass by value. This makes it consistent with other C family languages, and means that you never need to remember whether the situation you're looking at is pass by value or not.

From that link:

As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter. For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to. (See the next section for a discussion of how this affects method receivers.)

Then later:

  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 examples) 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 act as references, 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.

这篇关于为什么接收者在Go中通过价值传递?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆