What happens when two embedded types provide the same field or method name?
Question 89HardGo 1.22 to 1.25
Selector resolution uses depth. The name at the shallowest depth wins and shadows any deeper ones. If two or more names exist at the same shallowest depth, the selector is ambiguous. Ambiguity is a compile error only when you actually use the selector, and the ambiguous method is silently dropped from the outer type's method set.
type Reader struct{}
func (Reader) Close() error { return nil }
type Writer struct{}
func (Writer) Close() error { return nil }
type RW struct {
Reader
Writer
}
func main() {
var rw RW
// rw.Close() // compile error: ambiguous selector rw.Close
rw.Reader.Close() // OK: explicit
// var _ io.Closer = rw // compile error: RW does not implement io.Closer
// (missing method Close) -- the ambiguity removes it
}
// Resolve by declaring the method at depth 0:
func (rw RW) Close() error {
return errors.Join(rw.Reader.Close(), rw.Writer.Close())
}
A related trap is accidental shadowing. Embedding a type with a method named String or Error (for example, embedding time.Time or an error type) promotes that method and silently changes how fmt prints your outer struct.
More on Interfaces, Methods & Embedding
- Q87What does this print? (no virtual dispatch with embedding)
- Q88Embedding
Tvs*T: how does each affect the method set of the outer struct? - Q90What is interface embedding, and what changed in Go 1.14 about overlapping methods?
- Q91Why would you embed an interface inside a struct? What is the danger?
- Q92When should you use
any(interface{}), and when are generics the better choice? - Q93What does
var _ io.Writer = (*MyWriter)(nil)do, and why is it used?