Embedding
Picture an employee form with a whole personal form glued into it: name, surname and the rest. On top of it, the employee form has one more field, "Company". HR reads the name straight off the employee sheet without first looking for the glued-in page.
Go works the same way. The type Employee should do everything a Person can and also store a company name. If you put Person into an ordinary field p Person, every access gets longer: e.p.Name, e.p.Greet(). The code works, but the name p adds nothing to such accesses. In Go a type can be embedded in a struct, and then its fields and methods are reachable directly:
package main
import "fmt"
type Person struct{ Name string }
type Employee struct {
Person
Company string
}
func (p Person) Greet() string { return "Hi, " + p.Name }
func main() {
e := Employee{Person: Person{Name: "Ann"}, Company: "Abyss"}
fmt.Println(e.Name, e.Greet()) // Ann Hi, Ann
}Let's walk through the example line by line:
Employeestarts with a field that has no name, only the typePerson.- The literal fills in the glued-in form with the value
Person{Name: "Ann"}, and the fieldCompanywith the string"Abyss". e.Namereads the name straight frome.e.Greet()calls the method ofPerson, so the program printsAnn Hi, Ann.
The embedded field
A field given only a type, with no name, is called an embedded field, and the technique itself is embedding. The fields and methods of the embedded type are promoted to the outer struct:
- a field:
e.Namemeanse.Person.Name; - a method with a value receiver:
e.Greet()meanse.Person.Greet(); - a method with a pointer receiver: if
Greettook a*Person, the calle.Greet()on the variableewould still work.
An embedded field is part of the struct, like any other field. It has a name too, and that name is the name of its type. Two things follow:
- the literal says
Person: Person{Name: "Ann"}; - the whole
Personvalue is reached ase.Person.
If the embedded field is left out of the literal, it gets its zero value: in Employee{Company: "Abyss"} the field Name is empty.
Shadowing names
An own field of the outer struct with the same name shadows the promoted one. An own method Greet would hide the promoted one the same way. The embedded field stays reachable through the type's name:
type Manager struct {
Person
Name string
}m := Manager{Person: Person{Name: "Ann"}, Name: "Boss"}
fmt.Println(m.Name, m.Person.Name, m.Greet()) // Boss Ann Hi, AnnLet's see what the second line prints:
m.Nameis the own field ofManager, soBoss.m.Person.Nameis the field of the embeddedPerson, soAnn.m.Greet()returnsHi, Ann: the methodGreetis declared onPersonand sees only the fields ofPerson.
The method Greet does not know about the Manager type's own field Name. The glued-in form has no idea it sits inside another one.
Not inheritance
In languages with inheritance, a derived type counts as its base type and can stand in for it. Embedding does not work that way: Employee contains a Person value but does not become a Person itself. A method of the embedded type always works with its own value and never calls the methods of the outer type.
Interviewers like to ask: "Is embedding in Go inheritance?" The answer is no:
- the outer struct contains the inner one as an ordinary field;
- the inner one's fields and methods are reachable by a shorter path;
Employeedoes not become aPersonand cannot stand in for it.
This is also where the form picture ends: HR may accept an employee sheet as a personal form, but the compiler will not.
Common mistake
An Employee is passed where a Person is expected:
func greet(p Person) string { return "Hello, " + p.Name }
func main() {
e := Employee{Person: Person{Name: "Ann"}, Company: "Abyss"}
fmt.Println(greet(e)) // ✗
}cannot use e (variable of struct type Employee) as Person value in argument to greetThe program does not compile: Employee and Person are different types, even when one is embedded in the other. Pass the embedded field explicitly: greet(e.Person).
Key points
- An embedded field is a field with only a type and no name; its fields and methods are promoted to the outer struct.
- An own field or method with the same name shadows the promoted one, and the embedded value is reachable as
e.Person. - Embedding is not inheritance: an
Employeedoes not become aPersonand cannot be passed in its place.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.