Golang指针

I am currently learning to program with Go language. I am having some difficulties understanding Go pointers (and my C/C++ is far away now...). In the Tour of Go #52 (http://tour.golang.org/#52) for example, I read:

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())
}

But if instead of

func (v *Vertex) Abs() float64 {
[...]
v := &Vertex{3, 4}

I wrote:

func (v Vertex) Abs() float64 {
[...]
v := Vertex{3, 4}

Or even:

func (v Vertex) Abs() float64 {
[...]
v := &Vertex{3, 4}

and vice-versa:

func (v *Vertex) Abs() float64 {
[...]
v := Vertex{3, 4}

I got the exact same result. Is there a difference (memory-wise, etc)?

There are two different rules of the Go language used by your examples:

  1. It is possible to derive a method with a pointer receiver from a method with a value receiver. Thus func (v Vertex) Abs() float64 will automatically generate an additional method implementation:

    func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X+v.Y*v.Y) }
    func (v *Vertex) Abs() float64 { return Vertex.Abs(*v) }  // GENERATED METHOD
    

    The compiler will automatically find the generated method:

    v := &Vertex{3, 4}
    v.Abs()  // calls the generated method
    
  2. Go can automatically take the address of a variable. In the following example:

    func (v *Vertex) Abs() float64 { return math.Sqrt(v.X*v.X+v.Y*v.Y) }
    func main() {
        v := Vertex{3, 4}
        v.Abs()
    }
    

    the expression v.Abs() is equivalent to the following code:

    vp := &v
    vp.Abs()
    

The difference is pass-by-referenve vs pass-by-value.

In func f(v Vertex) the argument is copied into parameter v. In func f(v *Vertex) a pointer to an existing Vertex instance is passed.

When using methods, some of the dereferencing can be done for you, so you can have a method func (v *Vertex) f() and call it without taking a pointer first: v := Vertex{...}; v.f(). This is just a grain of syntax sugar, AFAIK.

There are differences. For example, the non-pointer receiver form forces the method to work on a copy. This way the method is not able to mutate the instance it was invoked on - it can access only the copy. Which might be ineffective in terms of e.g. time/memory performance/consumption etc.

OTOH, pointer to instances and methods with pointer receivers allow for easy instance sharing (and mutating) where desirable.

More details here.

There are two main differences in those examples:

func (v *Vertex) Abs()....

The receiver will be passed-by-reference for v and you would be able to call this method only on pointers:

v := Vertex{1,3}
v.Abs() // This will result in compile time error
&v.Abs() // But this will work

On the other hand

func (v Vertex) Abs() ....

You can call this method on both pointers and structs. The receiver will be passed-by-value even when you call this method on pointers.

v := Vertex{1,3}
v.Abs() // This will work, v will be copied.
&v.Abs() // This will also work, v will also be copied.

You can declare both func (v *Vertex) and func (v Vertex).

As the specification says

A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m():

In your case v.Abs() is shorthand for &v.Abs() if method is addressable.