Is struct embedding inheritance? How does method promotion work?
Question 86MediumGo 1.22 to 1.25
No. Embedding is composition with automatic delegation. An embedded field is an ordinary field named after its type, and the compiler promotes its fields and methods so they can be reached through the outer struct. A promoted method call is rewritten to a call on the inner value: outer.Log() becomes outer.Logger.Log(), and the receiver is still the inner value.
type Logger struct{ prefix string }
func (l *Logger) Log(msg string) { fmt.Println(l.prefix + msg) }
type Server struct {
*Logger // embedded; field name is "Logger"
addr string
}
s := Server{Logger: &Logger{"[srv] "}, addr: ":8080"}
s.Log("started") // promoted: s.Logger.Log("started")
type Loggable interface{ Log(string) }
var _ Loggable = s // Server satisfies Loggable through promotion
// var l *Logger = &s // compile error: no subtype relation
Embedding is not inheritance for several reasons:
- A
Serveris not aLogger. You cannot pass it where a*Loggeris expected. - There is no virtual dispatch. The inner type's methods never call back into the outer type's methods.
- There is no
super. You calls.Logger.Logexplicitly.
The outer type does satisfy interfaces through promoted methods, which gives you polymorphism without subtyping.
More on Interfaces, Methods & Embedding
- Q84Compare
v := x.(T)withv, ok := x.(T). What happens whenTis an interface type? - Q85Explain type switch semantics. What does this print?
- Q87What does this print? (no virtual dispatch with embedding)
- Q88Embedding
Tvs*T: how does each affect the method set of the outer struct? - Q89What happens when two embedded types provide the same field or method name?
- Q90What is interface embedding, and what changed in Go 1.14 about overlapping methods?