Go DISCUSSION

Go methods: when should I use a pointer receiver instead of a value receiver?

Started by prem pointer receivervalue receivermethod setsGo interfacesescape analysis
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

Go methods: when should I use a pointer receiver instead of a value receiver?

prem Go Forum
#1

I have type Counter struct { n int } with a method func (c Counter) Inc() { c.n++ }. Calling c.Inc() three times leaves c.n at 0. Changing the receiver to (c *Counter) fixes it, but then assigning a Counter value to my Incrementer interface fails with "Counter does not implement Incrementer (method Inc has pointer receiver)".

What are the rules for choosing between value and pointer receivers, why does the interface assignment break, and is passing pointers everywhere faster or slower in Go?

Community replies 4

Re: Go methods: when should I use a pointer receiver instead of a value receiver?

#2

A method receiver is an ordinary parameter. With func (c Counter) Inc() each call copies the struct into c; c.n++ increments the copy, which is discarded on return. With func (c *Counter) Inc() the method receives the address and modifies the original.

Go inserts the address-of operation for you on a direct call: if c is an addressable variable of type Counter, c.Inc() is compiled as (&c).Inc(). In the other direction, a pointer calling a value-receiver method is dereferenced automatically. Everything in Go is passed by value; to let a function modify the caller's struct you pass a pointer to it.

Re: Go methods: when should I use a pointer receiver instead of a value receiver?

#3

The interface error comes from method sets. The method set of type T contains only the methods declared with a value receiver. The method set of *T contains both value-receiver and pointer-receiver methods. With Inc declared on *Counter, only *Counter implements Incrementer, so var i Incrementer = Counter{} fails and var i Incrementer = &Counter{} works.

The automatic address-of cannot apply here, because the value stored in an interface is a copy and is not addressable. A pointer-receiver method would modify a hidden copy, so the language forbids it instead of quietly doing the wrong thing. For the same reason Counter{}.Inc() on a temporary and m["a"].Inc() on a map element do not compile.

Re: Go methods: when should I use a pointer receiver instead of a value receiver?

#4

The usual guidelines: use a pointer receiver if the method modifies the receiver, if the struct contains a sync.Mutex or another field that must not be copied, or if the struct is large. Use value receivers for small value-like types such as time.Time or a two-field point, and for map, channel and function types, which are references already.

Then be consistent. If any method of a type needs a pointer receiver, give all of its methods pointer receivers. The method set is then the same however the value is held, and nobody copies the struct by accident. go vet reports copies of values that contain a lock through its copylocks check.

Re: Go methods: when should I use a pointer receiver instead of a value receiver?

#5

On performance there is no universal winner. Copying a struct of a few words is a handful of register moves and keeps the value on the stack. Taking a pointer can make the value escape to the heap when the compiler cannot prove that the pointer does not outlive the function, and an allocation plus garbage-collection work often costs more than copying 16 or 32 bytes. For structs of hundreds of bytes the copy dominates and pointers win. go build -gcflags=-m prints the escape-analysis decisions, and go test -bench . -benchmem shows allocations per operation.

One correctness trap: for _, c := range counters { c.Inc() } over a slice of values increments a copy of each element, even with a pointer receiver. Use for i := range counters { counters[i].Inc() } or store []*Counter.

TEP COMMUNITY