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
nilpointers. Methods with value receivers whill cause a panic of called on anilvalue.