Go by Example: Method Sets
Method sets determine which types satisfy an interface. This example explores the subtle rules governing why *T satisfies interfaces that T does not.
Code
package main
import "fmt"
type Shaper interface {
Scale(f float64)
Area() float64
}
type Square struct {
Size float64
}
// Pointer receiver: Part of method set of *Square
func (s *Square) Scale(f float64) {
s.Size *= f
}
// Value receiver: Part of method set of Square AND *Square
func (s Square) Area() float64 {
return s.Size * s.Size
}
func main() {
sq := Square{5}
// 1. Assigning *Square to interface
// Works! *Square has both Scale (*Square) and Area (Square) in its set.
var s1 Shaper = &sq
s1.Scale(2)
fmt.Println("Area:", s1.Area())
// 2. Assigning Square to interface
// ERROR! Square only has Area(). It does NOT have Scale().
// var s2 Shaper = sq
// Compiler error: Square does not implement Shaper
// (Scale method has pointer receiver)
// 3. Calling methods directly
// This works because of Go's syntactic sugar for addressable values.
sq.Scale(5) // Converted to (&sq).Scale(5)
}
Explanation
The concept of "method sets" is a rigorous specification in Go's type system that determines interface satisfaction, often revealing itself through subtle compile-time errors when assigning concrete types to interfaces. The rule is precise: the method set of a concrete type T consists only of methods declared with a value receiver, whereas the method set of the corresponding pointer type *T includes both methods declared with a pointer receiver and those with a value receiver. This asymmetry exists because a pointer can always be dereferenced to access the value, but a value stored in an interface is not necessarily addressable, meaning the runtime cannot guarantee it can safely pass a pointer to a method that expects to mutate state.
This distinction explains why a type *T can satisfy an interface requiring a pointer-receiver method, but the value type T cannot; if an interface method modifies the receiver, the interface must hold a pointer to ensure those modifications persist on the original data. While Go provides syntactic sugar allowing you to call pointer methods on addressable value variables (e.g., myVal.PointerMethod()), this convenience does not extend to interface assignment, where the strict method set rules apply. Understanding method sets is therefore essential for designing interfaces and ensuring that your types implement them correctly without encountering unexpected "does not implement" errors.
- Method Set of T: Only value receiver methods.
- Method Set of *T: Both value AND pointer receiver methods.
- Interface Satisfaction: A type implements an interface only if its method set contains all required methods.
- Addressability: You can't take the address of a value stored inside an interface.

