Methods are how Go types get behaviour, and the receiver choice decides which interfaces a type satisfies.
A method is a function with a receiver declared before its name:
func (r Rect) Area() float64 { return r.W * r.H }You can define methods on any named type declared in the same package — structs, but also type Celsius float64 or type IDs []int. You can't add methods to types from other packages (wrap them in your own type instead).
The receiver can be a value (r Rect) or a pointer (r *Rect):
- A pointer receiver is required if the method modifies the receiver, and is preferable when the struct is large or contains things that must not be copied, such as a
sync.Mutex. - A value receiver works on a copy; it suits small, immutable types like
time.Timeor aPoint. - Be consistent: if any method needs a pointer receiver, give them all pointer receivers.
Calls are convenient: if v is addressable, v.Scale(2) automatically becomes (&v).Scale(2), and a pointer automatically dereferences for value methods. The difference shows up with interfaces: the method set of T contains only value-receiver methods, while *T has both. So if Scale has a pointer receiver, only *Rect — not Rect — satisfies an interface that requires Scale.
A nil pointer can still call a pointer-receiver method; the method just receives nil. Some types use this deliberately, but usually it ends in a nil dereference inside the method.
Method values, f := r.Area, bind the receiver and can be passed around like any function.
Example
package main
import "fmt"
type Counter struct {
name string
n int
}
func (c *Counter) Inc() { c.n++ } // modifies: pointer receiver
func (c *Counter) String() string { return fmt.Sprintf("%s=%d", c.name, c.n) }
type Celsius float64
func (c Celsius) Fahrenheit() float64 { return float64(c)*9/5 + 32 }
func main() {
c := Counter{name: "hits"}
c.Inc() // Go takes &c automatically
c.Inc()
fmt.Println(c.String()) // hits=2
fmt.Println(Celsius(100).Fahrenheit()) // 212
}Remember
- Pointer receivers to mutate or avoid copying; value receivers for small immutable types
- Methods can be declared on any named type in your package
- Pointer-receiver methods are not in the value type's method set
Watch out for
- Mixing value and pointer receivers on one type, then being surprised when T doesn't satisfy an interface.