Go by Example: Embedding
Understand Struct Embedding, Go's mechanism for type composition. This example demonstrates how to embed one struct into another, promoting fields and methods to the outer struct and achieving inheritance-like behavior through composition.
Code
package main
import "fmt"
type base struct {
num int
}
func (b base) describe() string {
return fmt.Sprintf("base with num=%v", b.num)
}
type container struct {
base // Embedding
str string
}
func main() {
co := container{
base: base{num: 1},
str: "some name",
}
// Access fields directly
fmt.Printf("co={num: %v, str: %v}\n", co.num, co.str)
// Access full path
fmt.Println("also num:", co.base.num)
// Call embedded methods
fmt.Println("describe:", co.describe())
// Interface implementation via embedding
type describer interface {
describe() string
}
var d describer = co
fmt.Println("describer:", d.describe())
}Explanation
Go supports struct embedding to express composition in a more seamless way than explicit field composition. When a struct is embedded anonymously (without providing a field name), its fields and methods are automatically promoted to the outer struct. This promotion means you can access the embedded struct's members as if they belonged directly to the outer struct, providing inheritance-like syntax while maintaining composition semantics.
Field and method promotion allows accessing inner struct members directly on the outer struct instance, reducing syntactic overhead. For example, co.num directly accesses the num field from the embedded base struct without needing co.base.num. However, the full path remains available when needed, such as resolving naming conflicts when multiple embedded structs have fields with the same name.
Embedding is often used to achieve inheritance-like behavior and code reuse, but it's fundamentally different from classical inheritance. The embedded struct has no knowledge of the outer struct that contains it—there's no parent-child relationship. If the embedded type implements an interface, the embedding type automatically satisfies that interface too (interface promotion). This makes embedding particularly powerful for building layered abstractions and decorators while maintaining Go's composition-over-inheritance philosophy.

