在Go中可以使用什么指针? [英] What pointers may be used for in Go?
问题描述
我想我明白指针是什么,但我不明白何时使用它。
下面的代码片段来自Go Tour of Go。
* Vertex和& Vertex的目的是什么?
我用Vertex取代了它们,它运行良好。
I think I understand what pointer is but I don't quite understand when to use it.
The below snippet is from "A Tour of Go".
What is the purpose of "*Vertex" and "&Vertex"?
I replaced them with "Vertex" and it run fine.
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())
}
推荐答案
这不是指针/值区分的特别好例子,因为在那种情况下它们是可以互换的!指针是非常有用的,当你需要远程(从另一个函数)改变数据。
That's not a particularly good example of the pointer/value distinction, because in that case they're interchangeable! Pointers are useful when you need to mutate data "remotely" (from another function).
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}
。尝试改为:
As you'll note, this doesn't change anything (strictly speaking, it changes a copy of the vertex, but that's just semantics in most cases)! The value of v
is still {3,4}
. Trying instead with:
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:=顶点{3,4}
。事实上,上述片段仍然有效。奇怪。同样,如果您在第二个片段中更改同一行以包含指针,它也会以同样的方式工作。
And suddenly, it works, the second time it prints {1,4}
. Now, if you're curious, you may decide to experiment and change v := &Vertex{3, 4}
to v := Vertex{3, 4}
. Indeed, the above snippet still works. Strange. Likewise, if you change the same line in the second snippet to contain a pointer, it also works the same way.
为什么? Go有透明的指针。在其他具有显式指针值(如C或C ++)的语言中,必须明确使用操作符&
和 *
来取消引用一个指针。 C和C ++甚至还有针对字段访问和方法调用的特殊语法 v-> SetX
。
Why? Go has "transparent" pointers. In other languages with explicit pointer values like C or C++, you have to explicitly use the operators &
and *
to dereference a pointer. C and C++ even have special syntax for pointer chasing on field access and method calls v->SetX
.
无论更好还是更糟,Go都隐藏了这一点。如果你有一个值并且需要调用指针方法,Go会很乐意为你做(& v).Method()
,如果你需要解引用来调用值的方法,它很高兴地自动执行(* v).Method()
。在大多数情况下,这是真实的,有一些像地图这样的东西不适用的角落案件,但一般情况下这成立。
For better or worse, Go hides this from you. If you have a value and need to call a pointer method, Go will happily do (&v).Method()
for you, if you need to dereference to call a value method, it happily does (*v).Method()
automatically. This is true in most cases, there are a few corner cases with things like maps where this doesn't apply, but in general this holds.
所以,当它来回到它,什么时候应该在方法上使用指针接收器?答案实际上是大部分时间。 Go Style Guide 一般建议使用指针类型方法接收器,但当接收者是 map
, func
或 chan $的直接别名时c $ c>,它是一个不需要重新分片的分片,或者你正在对小的不可变数据类型进行优化(因为指针追逐比复制慢一点)。我会补充说,你通常不应该使用直接指针指针。
So, when it comes down to it, when should you use a pointer receiver on a method? The answer, really, is "most of the time." The Go Style Guide generally recommends using pointer type method receivers except when the receiver is a direct alias for a map
, func
, or chan
, it's a slice that doesn't need reslicing, or you're doing optimizations on small, immutable data types (because pointer chasing is a little bit slower than copying). I'd add to that that you generally shouldn't use direct pointers to pointers.
一般来说,当你不知道要使用哪一个时,使用指针接收器。 99%的时间使用指针会给你你期望的行为,特别是如果你习惯Python或C#等语言。错误地使用指针导致错误的情况相对较少,因为你的Setter方法实际上没有设置任何东西,因此比较了得到错误的可能性。
Generally, when you have no idea which to use, use a pointer receiver. 99% of the time using a pointer will give you the behavior you expect, especially if you're used to languages like Python or C#. It's comparatively rare that incorrectly using a pointer causes a bug, compared the probability of getting a bug because your Setter method isn't actually setting anything.
这篇关于在Go中可以使用什么指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!