SyntaxStudy
Sign Up
Go Struct Embedding and Composition
Go Beginner 1 min read

Struct Embedding and Composition

Go achieves code reuse through composition rather than inheritance. Struct embedding allows one struct to include another as an anonymous (embedded) field. The outer struct automatically promotes all the exported methods and fields of the embedded type, making them accessible as if they were defined directly on the outer struct. Embedding is not inheritance: the embedded type does not know about the outer type, and there is no polymorphism through embedding alone. However, combined with interfaces, embedding enables powerful and flexible designs. If the outer struct needs to override a promoted method, it simply defines its own method with the same name. Multiple structs can be embedded, and embedding works with both value types and pointer types. Embedding a pointer is common when the embedded type is large or when multiple outer structs should share the same instance of the embedded type. This pattern is widely used in the Go standard library, for example in the `http.ResponseWriter` chain.
Example
package main

import "fmt"

// Base type
type Animal struct {
    Name string
}

func (a Animal) Speak() string {
    return a.Name + " makes a sound."
}

func (a Animal) Describe() string {
    return fmt.Sprintf("I am %s", a.Name)
}

// Dog embeds Animal
type Dog struct {
    Animal          // anonymous (embedded) field
    Breed  string
}

// Dog overrides Speak
func (d Dog) Speak() string {
    return d.Name + " says: Woof!"
}

// Logger shows embedding for cross-cutting concerns
type Logger struct {
    Prefix string
}

func (l Logger) Log(msg string) {
    fmt.Printf("[%s] %s\n", l.Prefix, msg)
}

type Service struct {
    Logger              // embedded logger
    Name   string
}

func (s *Service) Start() {
    s.Log("starting service: " + s.Name) // promoted method
}

func main() {
    d := Dog{
        Animal: Animal{Name: "Rex"},
        Breed:  "Labrador",
    }

    fmt.Println(d.Speak())       // Dog's own method
    fmt.Println(d.Describe())    // promoted from Animal
    fmt.Println(d.Name)          // promoted field

    svc := Service{
        Logger: Logger{Prefix: "INFO"},
        Name:   "AuthService",
    }
    svc.Start()
}