Receivers in Go are methods (behaviours) tightly coupled to a specific type
. A receiver is defined in between func
and the name of the method.
type Counter struct {
Count int
}
func (ctr Counter) Increment () {
ctr.Count++
}
This Increment
method acts on a struct of type Counter
.
Value Receivers vs. Pointer Receivers
Value
The above is an example of a value receiver ctr Counter
. The method acts on a copy of the value ctr
. Changes made inside the method do not affect the original value. This is because Go is pass-by-value, meaning it creates a copy within the function.
type Counter struct {
Count int
}
func (ctr Counter) Increment () {
ctr.Count++
}
func main() {
myCounter := Counter{Count: 0}
myCounter.Increment()
println("Count:", myCounter.Count) // 0
}
Pointer
Also known as passing by reference, when you pass a pointer as the receiver type (ctr *Counter
below), the method acts on the actual value. This is often used to avoid the overhead of copying large structs.
type Counter struct {
Count int
}
func (ctr *Counter) Increment () {
ctr.Count++
}
func main() {
myCounter := Counter{Count: 0}
myCounter.Increment()
println("Count:", myCounter.Count) // 1
}
Which receiver type to use
TL;DR - you almost always want to use a pointer receiver, especially if:
- You are updating the state of the receiver (changing the value)
- You want to avoiding copying large structs
- You want consistency with all methods for a type. If some methods use a pointer receiver, they can all use pointer receivers.
- You want to use
nil
pointers. Methods with value receivers whill cause a panic of called on anil
value.