[英]Golang pointers
我目前正在学习用Go语言编程。 我在理解Go指针方面遇到了一些困难(现在我的C / C ++还很远......)。 例如,在Tour of Go#52( http://tour.golang.org/#52 )中,我读到:
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Println(v.Abs())
}
但如果不是
func (v *Vertex) Abs() float64 {
[...]
v := &Vertex{3, 4}
我写:
func (v Vertex) Abs() float64 {
[...]
v := Vertex{3, 4}
甚至:
func (v Vertex) Abs() float64 {
[...]
v := &Vertex{3, 4}
反之亦然:
func (v *Vertex) Abs() float64 {
[...]
v := Vertex{3, 4}
我得到了完全相同的结果。 是否存在差异(记忆方面等)?
您的示例使用了两种不同的Go语言规则:
可以从具有值接收器的方法导出具有指针接收器的方法。 因此func (v Vertex) Abs() float64
将自动生成另一个方法实现:
func (v Vertex) Abs() float64 { return math.Sqrt(vX*v.X+vY*vY) } func (v *Vertex) Abs() float64 { return Vertex.Abs(*v) } // GENERATED METHOD
编译器将自动找到生成的方法:
v := &Vertex{3, 4} v.Abs() // calls the generated method
Go可以自动获取变量的地址。 在以下示例中:
func (v *Vertex) Abs() float64 { return math.Sqrt(vX*v.X+vY*vY) } func main() { v := Vertex{3, 4} v.Abs() }
表达式v.Abs()
等效于以下代码:
vp := &v vp.Abs()
有区别。 例如,非指针接收器形式强制该方法在副本上工作。 这样,该方法无法改变它所调用的实例 - 它只能访问该副本。 在时间/内存性能/消耗等方面可能无效。
OTOH,指向具有指针接收器的实例和方法的指针允许在需要时容易地实例共享(和变异)。
更多细节在这里 。
区别在于传递参考与传递值。
在func f(v Vertex)
,参数被复制到参数v
。 在func f(v *Vertex)
中,传递指向现有Vertex
实例的指针。
使用方法时,可以为您完成一些解除引用,因此您可以使用方法func (v *Vertex) f()
并在不先获取指针的情况下调用它: v := Vertex{...}; vf()
v := Vertex{...}; vf()
。 这只是一种语法糖,AFAIK。
这些例子有两个主要区别:
func (v *Vertex) Abs()....
接收器将通过引用传递给v,你只能在指针上调用此方法:
v := Vertex{1,3}
v.Abs() // This will result in compile time error
&v.Abs() // But this will work
另一方面
func (v Vertex) Abs() ....
您可以在指针和结构上调用此方法。 即使您在指针上调用此方法,接收器也将按值传递 。
v := Vertex{1,3}
v.Abs() // This will work, v will be copied.
&v.Abs() // This will also work, v will also be copied.
您可以声明func (v *Vertex)
和func (v Vertex)
。
正如规范所说
如果方法集x(类型)x包含m并且参数列表可以分配给m的参数列表,则方法调用xm()有效。 如果x是可寻址的并且&x的方法集包含m,则xm()是(&x).m()的简写:
在你的情况下,如果方法是可寻址的,v.Abs()是&v.Abs()的简写。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.