tezvyn:

Value versus pointer receivers and interface satisfaction

AI-drafted, machine-checkedSource: interviewintermediate
WHAT IT TESTS

method sets and interface satisfaction.

OUTLINE

value-receiver methods belong to both T and *T, but pointer-receiver methods belong only to *T, so a value of T may not satisfy an interface.

WHAT THIS TESTS Whether you understand Go method sets and can predict when a value versus a pointer satisfies an interface, plus the mutation and copying implications.

A GOOD ANSWER COVERS A value receiver method receives a copy of the value, so it cannot mutate the original and is cheap only for small types. A pointer receiver receives the address, so it can mutate the original and avoids copying large structs. The crucial consequence is method sets. The method set of T includes only its value-receiver methods. The method set of *T includes both value-receiver and pointer-receiver methods. Interface satisfaction is checked against the method set. So if an interface requires a method declared with a pointer receiver, only *T satisfies the interface; a plain T value does not, and you must use a pointer. If every required method uses a value receiver, both T and *T satisfy it.

COMMON WRONG ANSWERS Thinking a value always satisfies the interface regardless of receiver. Believing Go auto-takes the address of any value; it only does so for addressable values, not, for example, a value stored in a map or returned from a function. Mixing receiver kinds on one type without reason, which is discouraged. Assuming value receivers can mutate.

LIKELY FOLLOW-UPS Why can a *T call value-receiver methods but not vice versa for non-addressable values. When should a type use pointer receivers throughout. How do nil pointer receivers behave. Copy cost considerations.

ONE CONCRETE EXAMPLE Define type Counter with Increment using a pointer receiver because it mutates a field. An interface Incrementer requires Increment. A Counter value does not satisfy Incrementer because Increment is in the method set of *Counter only; you must pass &counter. If you store a Counter in a map and try to call the pointer method, it fails to compile because map values are not addressable, so you cannot take their address implicitly.

Read the original → go.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.