Struct Embedding & Composition

Embedding places one type inside another with no field name so its fields and methods are promoted onto the outer type — Go's way of reusing code through composition instead of inheritance.

Learn Struct Embedding & Composition in our free Go course — an interactive lesson with runnable examples, a practice exercise and a quick reference.

Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Embedding a Struct (Promoted Fields)

To embed, list a type inside a struct with no field name . The embedded type's fields are then promoted : you reach u.City directly even though City belongs to the inner Address . The inner value is still there under its type name ( u.Address.City ), and reads and writes through either path touch the same data.

2️⃣ Promoted Methods & Overriding

Methods are promoted too: a Dog that embeds Animal automatically has Animal 's methods. If you define a method with the same name on the outer type, it overrides (shadows) the promoted one — Go picks the shallowest match. The inner method is still reachable explicitly via the type name ( d.Animal.Speak() ), which lets an override extend rather than fully replace the original.

3️⃣ Embedding an Interface

You can embed an interface as well, which is the idiomatic way to decorate behaviour. Embed the interface, override only the methods you want to change, and delegate the rest to the embedded value. Below, LoggedSorter embeds sort.Interface and counts swaps while passing the real work through to the wrapped sorter.

🎯 Your Turn

Embed Engine in Car so you can read c.HP directly. Fill in the two blanks.

Build a Widget that embeds Base , adds a Label , and overrides Info() so it calls the embedded Base.Info() inside its own output.

Practice quiz

How do you embed a type in a struct?

  • Give it a field name like Addr Address
  • Use the embed keyword
  • List the type with no field name
  • Wrap it in a pointer always

Answer: List the type with no field name. Embedding lists a type with no field name; that promotes its fields and methods.

If User embeds Address (with a City field), how do you read City directly?

  • u.City

Answer: u.City. Promoted fields are reachable directly: u.City works as well as u.Address.City.

Does Go have class inheritance?

  • Yes, via embedding
  • Yes, with the extends keyword
  • Only for interfaces
  • No — embedding is composition, not inheritance

Answer: No — embedding is composition, not inheritance. Go has no inheritance; embedding is composition that promotes members.

How do you override a promoted method?

  • Use the override keyword
  • Define a method with the same name on the outer type
  • Delete the inner method
  • You cannot override it

Answer: Define a method with the same name on the outer type. Defining a same-named method on the outer type shadows the promoted one.

After Dog overrides Speak, how do you still call the embedded Animal's Speak?

  • d.Animal.Speak()
  • d.Speak()
  • Animal.Speak(d)
  • super.Speak()

Answer: d.Animal.Speak(). The inner method stays reachable explicitly via the type name: d.Animal.Speak().

How do you initialise an embedded field in a struct literal?

  • By a made-up field name
  • It is always zero-valued
  • By its type name, e.g. Address: Address{...}
  • With the embed: keyword

Answer: By its type name, e.g. Address: Address{...}. There is no separate name; you use the type name: User{Address: Address{...}}.

What happens if two embedded types both have a field named Name and you write v.Name?

  • Go picks the first one
  • It is an ambiguous selector — a compile error
  • It returns both
  • It panics at runtime

Answer: It is an ambiguous selector — a compile error. Direct use of an ambiguous promoted name is a compile error; qualify by type to resolve.

How do you resolve an ambiguous embedded name?

  • Rename the struct
  • Use a pointer
  • Remove one embed
  • Qualify it by type, e.g. v.TypeA.Name

Answer: Qualify it by type, e.g. v.TypeA.Name. Qualify with the type name (v.TypeA.Name) to disambiguate.

Why embed an interface (like sort.Interface) instead of a struct?

  • It is faster
  • To wrap/decorate an implementation, overriding some methods and delegating the rest
  • Interfaces cannot be fields otherwise
  • To avoid promotion

Answer: To wrap/decorate an implementation, overriding some methods and delegating the rest. Embedding an interface lets you decorate behaviour: override what you need, delegate the rest.

In LoggedSorter, how does the overriding Swap forward to the embedded implementation?

  • s.Swap(i, j)
  • super.Swap(i, j)
  • s.Interface.Swap(i, j)
  • sort.Swap(i, j)

Answer: s.Interface.Swap(i, j). It delegates to the embedded value via s.Interface.Swap(i, j).