为什么带有指针接收器的方法在收到值时仍然有效?

时间:2013-08-01 14:24:51

标签: pointers methods go

我刚刚和Exercise 51 in the Tour of Go一起玩。该解释声明Scale方法在收到Vertex而不是指向Vertex的指针时无效。

然而,当我在v := &Vertex{3, 4}中将声明v := Vertex{3, 4}更改为main时,输出中唯一的变化就是缺少标记指针的&

那么为什么Scale改变它收到的变量,即使变量不是指针?

2 个答案:

答案 0 :(得分:8)

它没有“收到”一个值。 Go是强类型的,所以如果在某处指定了指向T的指针,则指向T(*T)的指针是唯一可以作为此类型位置的值的选项。

“魔术”在编译器中,可以在某些conditions下有效地“重写”您的代码:

  

如果方法集{(1)}的x.m()包含x并且参数列表可以分配给{{1}的参数列表,则方法调用m有效}。如果m是可寻址的且& x的方法集包含x,则mx.m()的简写:

相关:Method sets

答案 1 :(得分:1)

巡回建议的差异实际上并不是在将v := &Vertex{3, 4}更改为v:= Vertex{3, 4},而是更改两种方法的定义,以便它们可以处理值而不是指针。因此,例如,对于Scalefunc (v *Vertex) Scale(f float64) {...变为func (v Vertex) Scale(f float64) {...(注意(v *Vertex),指针值变为(v Vertex),非指针值)。在这两种情况下,您都应将v的声明保留为v := &Vertex{3, 4}

您会注意到,在第一种情况下,当方法采用指针时,输出为&{15 20} 25。但是,当方法采用值而不是指针时,输出为&{3 4} 5

在这两种情况下,v都是指向Vertex对象的指针。在第一种情况下,指针被传递给方法,并且一切都按预期工作 - 对Vertex对象所做的任何修改都是对原始值进行的,因此这些更改在方法返回后仍然存在。在第二种情况下,虽然v仍然是指针,但Go编译器足够聪明,可以将v.Scale(5)转换为(*v).Scale(5),其中v被解除引用,结果值为传递给Scale