在Go中可以使用什么指针? [英] What pointers may be used for in Go?

查看:168
本文介绍了在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 ,它是一个不需要重新分片的分片,或者你正在对小的不可变数据类型进行优化(因为指针追逐比复制慢一点)。我会补充说,你通常不应该使用直接指针指针。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆