Struct Embedding
fmtGo supports embedding of structs and interfaces to express a more seamless composition of types. Go has no inheritance; embedding is how types reuse each other.
package main
import "fmt"
type base struct {
num int
}
func (b base) describe() string {
return fmt.Sprintf("base with num=%v", b.num)
}A container embeds a base. An embedding looks like a field without a name.
type container struct {
base
str string
}
func main() {When creating structs with literals, we initialize the embedding explicitly; the embedded type serves as the field name.
co := container{
base: base{
num: 1,
},
str: "some name",
}We can access the base's fields directly on co.
fmt.Printf("co={num: %v, str: %v}\n", co.num, co.str)Alternatively, spell out the full path using the embedded type name.
fmt.Println("also num:", co.base.num)Since container embeds base, the methods of base also become methods of a container. Here we call describe directly on co.
fmt.Println("describe:", co.describe())
type describer interface {
describe() string
}Embedding structs with methods can bestow interface implementations onto other structs. Here a container now implements the describer interface because it embeds base.
var d describer = co
fmt.Println("describer:", d.describe())Interfaces can embed other interfaces too, combining their methods.
type namer interface{ name() string }
type namedDescriber interface {
describer
namer
}
var _ namedDescriber = nil
fmt.Println("interfaces compose")
}$ go run ./23_struct_embedding co={num: 1, str: some name} also num: 1 describe: base with num=1 describer: base with num=1 interfaces compose