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