Go

How do you decide between value and pointer receivers?

Question 83MediumGo 1.22 to 1.25

Use a pointer receiver when any of these apply:

  • The method mutates the receiver.
  • The struct is large, so copying it on every call is expensive.
  • The struct contains fields that must not be copied (sync.Mutex, sync.WaitGroup, atomic.Int64, bytes.Buffer, or anything with a noCopy field).
  • Other methods of the type already use pointer receivers. Keep them consistent.

Use a value receiver for small, immutable value types (time.Time, a Point), for maps, funcs and chans (already reference-like), and for slices when the method does not reslice or append.

type Account struct {
    mu      sync.Mutex
    balance int64
}

// BUG: value receiver copies the mutex; each call locks its own copy
func (a Account) Balance() int64 {
    a.mu.Lock()
    defer a.mu.Unlock()
    return a.balance
}
// go vet: "Balance passes lock by value: Account contains sync.Mutex"

Mixing receiver kinds is legal, but it makes the method set of T a strict subset of the method set of *T, which confuses readers. A value receiver also gives weaker thread-safety than it appears to: the copy is taken when the method is called, and that copy can race with concurrent writers.

More on Interfaces, Methods & Embedding

All 35 Interfaces, Methods & Embedding questions