merlin Gaillard
merlin Gaillard

Reputation: 233

Golang pointers

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)?

Upvotes: 22

Views: 12658

Answers (5)

Kasinath Kottukkal
Kasinath Kottukkal

Reputation: 2589

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.

Upvotes: 0

ndyakov
ndyakov

Reputation: 37

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).

Upvotes: 0

user811773
user811773

Reputation:

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

Upvotes: 33

zzzz
zzzz

Reputation: 91409

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.

Upvotes: 13

9000
9000

Reputation: 40894

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.

Upvotes: 2

Related Questions