Pointer vs. value methods
suggest changePointer 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.