我想我明白指针是什么,但我不太明白何时使用它.
以下片段来自"A Tour of Go".
"*Vertex"和"&Vertex"的目的是什么?
我用"顶点"替换它们,它运行正常.
package main
import (
"fmt"
"math"
)
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())
}
Run Code Online (Sandbox Code Playgroud)
这不是指针/值区别的一个特别好的例子,因为在那种情况下它们是可以互换的!当您需要"远程"(从另一个函数)变异数据时,指针很有用.
func (v Vertex) SetX(x int) {
v.X = x
}
func main() {
v := Vertex{3, 4}
fmt.Println(v)
v.SetX(1)
fmt.Println(v)
}
Run Code Online (Sandbox Code Playgroud)
正如您将注意到的,这并没有改变任何东西(严格来说,它改变了顶点的副本,但在大多数情况下这只是语义)!价值v仍然是{3,4}.尝试改为:
func (v *Vertex) SetX(x int) {
v.X = x
}
func main() {
v := &Vertex{3, 4}
fmt.Println(v)
v.SetX(1)
fmt.Println(v)
}
Run Code Online (Sandbox Code Playgroud)
突然间,它第二次打印就有效了{1,4}.现在,如果你好奇,你可以决定尝试和改变v := &Vertex{3, 4}来v := Vertex{3, 4}.实际上,上面的片段仍然有用.奇怪.同样,如果您更改第二个代码段中的同一行以包含指针,它也会以相同的方式工作.
为什么?Go有"透明"指针.在具有显式指针值(如C或C++)的其他语言中,您必须显式使用运算符&并*取消引用指针.C和C++甚至在字段访问和方法调用上都有特殊的指针追逐语法v->SetX.
无论好坏,Go都会隐藏这一点.如果你有一个值并且需要调用指针方法,那么Go会很乐意(&v).Method()为你做,如果你需要取消引用来调用一个值方法,它会很自然地(*v).Method()自动完成.在大多数情况下都是如此,有一些像地图这样的东西不适用的极端情况,但总的来说这是成立的.
那么,当它归结为它时,你何时应该在方法上使用指针接收器?答案,确实是"大多数时候".在围棋风格指南通常建议使用指针类型的方法接收器除了当接收器是一个直接的别名map,func或者chan,它是不需要reslicing片,或者你正在做小的,一成不变的数据类型的优化(因为指针追逐比复制慢一点.我补充一点,你通常不应该使用直接指针指针.
通常,当您不知道使用哪个时,请使用指针接收器.99%的时间使用指针将为您提供所期望的行为,特别是如果您习惯使用Python或C#等语言.错误地使用指针导致错误是相对罕见的,比较获取错误的可能性,因为您的Setter方法实际上没有设置任何东西.