In Go, embedding is a mechanism that allows you to "inherit" the behavior of a struct by embedding one struct within another without using explicit inheritance, as in OOP. The embedded struct becomes anonymous fields of the new struct.
In this way, all methods of the embedded struct become methods of the new struct, as if they were "inherited".
Example:
package main import "fmt" type Animal struct { Name string } func (a Animal) Speak() { fmt.Println("My name is", a.Name) } type Dog struct { Animal // embedding, anonymous field Breed string } func main() { d := Dog{ Animal: Animal{Name: "Rex"}, Breed: "Shepherd", } d.Speak() // Inherited method! fmt.Println(d.Name) // Field is directly accessible }
The main difference between embedding and regular struct inclusion as a named field is:
"If the embedded struct and the outer struct contain fields with the same names, which one will be used and how to access them?"
Many believe that only the "outer" field will be used, but it works differently:
Example:
type Base struct { Name string } type Child struct { Base // embedding Name string // colliding field } c := Child{Base: Base{Name: "Base"}, Name: "Child"} fmt.Println(c.Name) // Child fmt.Println(c.Base.Name) // Base
Story
In a project, the standard struct for logging was embedded, and then a
Loggerfield was defined in the child type. As a result, calls tod.Logger.Info()did not work as expected because access to the embedded field was "lost" among the similarly named fields.
Story
A developer tried to override a method in the child struct, but methods do not "override" — a new one simply appears, and the parent method is still accessible as
Child.Base.Method(). This led to some code using the "old" version of the method, expecting different logic.
Story
During JSON serialization with embedded structs, unexpected results occurred: fields of the "embedded" struct appeared in the root object. Due to ignorance of how embedding affects marshaling, the struct was serialized incorrectly, breaking API backward compatibility.