Go

Embedding T vs *T: how does each affect the method set of the outer struct?

Question 88HardGo 1.22 to 1.25

For a struct S:

  • If S embeds T, the method sets of S and *S include the promoted methods with receiver T. Only *S also includes those with receiver *T.
  • If S embeds *T, the method sets of S and *S both include the promoted methods with receiver T and *T.
type T struct{}
func (T) A()  {}
func (*T) B() {}

type ByVal struct{ T }
type ByPtr struct{ *T }

type AB interface{ A(); B() }

// var _ AB = ByVal{}   // error: ByVal does not implement AB (method B has pointer receiver)
var _ AB = &ByVal{}     // OK
var _ AB = ByPtr{}      // OK: B reachable via the embedded pointer
var _ AB = &ByPtr{}     // OK

func main() {
    var p ByPtr         // p.T == nil
    p.A()               // panic: nil pointer dereference (A needs *p.T copied as value)
    p.B()               // fine if B does not touch fields; receiver is nil *T
}

The trade-offs:

  • Embedding a pointer lets several outer values share one inner value, lets you swap the inner value at runtime, and gives the value type the full method set.
  • The cost is that the zero value of the outer struct holds a nil pointer, which leads to panics. Copying the outer struct also shares state, which may be surprising.
  • Embedding by value makes the zero value usable, as with struct{ sync.Mutex }.

More on Interfaces, Methods & Embedding

All 35 Interfaces, Methods & Embedding questions