Essential Go Pointers  Suggest an edit

Pointer vs. value methods

Pointer Methods

Pointer methods can be called even if the variable is itself not a pointer.

According to the Go Spec,

. . . a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.

You can see this in this example:

type Foo struct {
	Bar int
}

func (f *Foo) Increment() {
	f.Bar++
}

func main() {
	var f Foo

	// Calling `f.Increment` is automatically changed to `(&f).Increment` by the compiler.
	f = Foo{}
	fmt.Printf("f.Bar is %d\n", f.Bar)
	f.Increment()
	fmt.Printf("f.Bar is %d\n", f.Bar)

	// As you can see, calling `(&f).Increment` directly does the same thing.
	f = Foo{}
	fmt.Printf("f.Bar is %d\n", f.Bar)
	(&f).Increment()
	fmt.Printf("f.Bar is %d\n", f.Bar)
}
f.Bar is 0
f.Bar is 1
f.Bar is 0
f.Bar is 1

Value Methods

Similarly to pointer methods, value methods can be called even if the variable is itself not a value.

According to the Go Spec,

. . . a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv.

You can see this in this example:

type Foo struct {
	Bar int
}

func (f Foo) Increment() {
	f.Bar++
}

func main() {
	var p *Foo

	// Calling `p.Increment` is automatically changed to `(*p).Increment` by the compiler.
	// (Note that `*p` is going to remain at 0 because a copy of `*p`, and not the original `*p` are being edited)
	p = &Foo{}
	fmt.Printf("(*p).Bar is %d\n", (*p).Bar)
	p.Increment()
	fmt.Printf("(*p).Bar is %d\n", (*p).Bar)

	// As you can see, calling `(*p).Increment` directly does the same thing.
	p = &Foo{}
	fmt.Printf("(*p).Bar is %d\n", (*p).Bar)
	(*p).Increment()
	fmt.Printf("(*p).Bar is %d\n", (*p).Bar)
}
(*p).Bar is 0
(*p).Bar is 0
(*p).Bar is 0
(*p).Bar is 0

To learn more about pointer and value methods, visit the Go Spec section on Method Values, or see the Effective Go section about Pointers v. Values.

Note 1: The parenthesis (()) around *p and &f before selectors like .Bar are there for grouping purposes, and must be kept.

Note 2: Although pointers can be converted to values (and vice-versa) when they are the receivers for a method, they are not automatically converted to each other when they are arguments inside of a function.

  ↑ ↓ to navigate     ↵ to select     Esc to close