Are the argument passing semantics for methods on structs purely determined by the method and not by the caller?

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

Are the argument passing semantics for methods on structs purely determined by the method and not by the caller?

问题

考虑以下简单的程序,我们在指向结构体Vertex的指针上定义一个方法,然后使用指针调用它。

package main

import (
	"fmt"
)

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Mutate() {
	v.X = 8
}

func main() {
	v := &Vertex{3, 4}
	v.Mutate()
	fmt.Println(v.X)
}

这个程序的输出是8,这是我们预期的,因为我们传递了一个指向方法的指针。

然而,下面的调用也会输出8

func main() {
	v := Vertex{3, 4}
	v.Mutate()
	fmt.Println(v.X)
}

相反地,如果我们将方法Mutate重新定义为接受一个Vertex而不是一个指针,那么无论传递的是指针还是结构体,突变都会失败。

这种行为似乎意味着传递的参数v或指向v的指针完全取决于方法的定义,而不是实际传递的内容。

这个解释正确吗?这种情况是否总是如此?如果不是,对于这种行为的正确解释是什么?

英文:

Consider the following simple program, where we define a method on a pointer to the struct Vertex and then invoke it with a pointer.

package main

import (
	"fmt"
)

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Mutate()  {
	v.X = 8
}

func main() {
	v := &Vertex{3, 4}
	v.Mutate()
	fmt.Println(v.X)
}

The output of this program is 8, which we expect because we are passing a pointer to a method which takes a pointer.

However, the following invocation also has an output of 8.

func main() {
	v := Vertex{3, 4}
	v.Mutate()
	fmt.Println(v.X)
}

Symmetrically, if we redefine the method Mutate to take a Vertex instead of a pointer, then the mutation fails regardless of whether a pointer or a struct is passed.

This behavior seems to imply that whether the argument v or a pointer to v to passed depends entirely on the definition of the method, rather than on what is actually being passed.

Is this a correct interpretation, and will this always be the case? If not, what is the correct explanation for this behavior?

答案1

得分: 3

这种行为似乎暗示了传递参数v或指向v的指针取决于方法的定义,而不是实际传递的内容。

不,这不是正确的解释,但几乎正确。

实际传递给方法的是一个指针,即使看起来像是v.Mutate(),其中v是一个非指针类型。原因是:你的v是"可寻址的",因此它的方法集包括指针类型的方法。详细信息请参阅http://golang.org/ref/spec#Calls。这是一种语法糖。因为v是可寻址的,你可以取得它的地址&v,然后在该指针上调用方法,如(&v).Mutate。这种语法很笨拙,Go会自动为可寻址的表达式完成这个操作。

(如果你对这些内容感兴趣,为什么不阅读整个语言规范呢?只需要3个小时就可以完成。)

英文:

> This behavior seems to imply that whether the argument v or a pointer to v to passed depends entirely on the definition of the method, rather than on what is actually being passed.
>
> Is this a correct interpretation, and will this always be the case? If not, what is the correct explanation for this behavior?

No, this is not correct but it is almost correct.

What gets passed to your method is a pointer, even if it looks like v.Mutate() with v a non-pointer. The reason is: Your v is "addressable" and thus its method set includes methods on the pointer type. See http://golang.org/ref/spec#Calls for details. This is a kind of syntactic sugar. Because v is addressable you may take its address &v and on this pointer you may invoke your method like (&v).Mutate. This syntax is clumsy and Go automatically does it for you for addressable expressions.

(If you are interested in such stuff, why not read the whole language specification? It can be done in 3 hours.)

huangapple
  • 本文由 发表于 2015年7月1日 05:53:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/31149191.html
匿名

发表评论

匿名网友

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

确定