Promoted fields and methods in Go

Struct is a sequence of fields each with name and type. Usually it looks like:

package main
import "fmt"
type Person struct {
name string
age int32
}
func main() {
person := Person{name: "Michał", age: 29}
fmt.Println(person) // {Michał 29}
}

(for the rest of this post I’ll omit package name, imports and main function definition).

Each field in the above struct has explicit name. Go additionally allows to skip field name. Field without name is called anonymous or embedded. Name of type (without package prefix if present) is then used as field name. Since struct has a requirement to have unique field names we can’t do:

import (
"net/http"
)
type Request struct{}
type T struct {
http.Request // field name is "Request"
Request // field name is "Request"
}

as compiler throws an error:

> go install github.com/mlowicki/sandbox
# github.com/mlowicki/sandbox
src/github.com/mlowicki/sandbox/sandbox.go:34: duplicate field Request

Having anonymous field its methods and fields are accessible in a concise way:

type Person struct {
name string
age int32
}
func (p Person) IsAdult() bool {
return p.age >= 18
}
type Employee struct {
position string
}
func (e Employee) IsManager() bool {
return e.position == "manager"
}
type Record struct {
Person
Employee
}
...
record := Record{}
record.name = "Michał"
record.age = 29
record.position = "software engineer"
fmt.Println(record) // {{Michał 29} {software engineer}}
fmt.Println(record.name) // Michał
fmt.Println(record.age) // 29
fmt.Println(record.position) // software engineer
fmt.Println(record.IsAdult()) // true
fmt.Println(record.IsManager()) // false

Fields and methods of anonymous (embedded) field are called promoted. They behave like regular fields but can’t be used in struct literals:

//record := Record{}
record := Record{name: "Michał", age: 29}

as it gives compiler error:

// src/github.com/mlowicki/sandbox/sandbox.go:23: unknown Record field ‘name’ in struct literal
// src/github.com/mlowicki/sandbox/sandbox.go:23: unknown Record field ‘age’ in struct literal

It’s possible though to create explicitly the whole embedded struct:

Record{Person{name: "Michał", age: 29}, Employee{position: "Software Engineer"}}

(credits to Juan Carlos Garcia)

Resources: