Struct embedding

Let's say we want to create a workshop based on our Course struct.

We could create a new struct Workshop and copy all the fields from Course into it. But that would be a lot of duplication.

Let's start by creating a new struct Workshop:

type Workshop struct {
    Course Course
    Date   time.Time
}

We can instantiate and print it:

func main() {
    var w = Workshop{
        Course: Course{Name: "Go", Instructor: Instructor{FirstName: "Lasse", LastName: "Jensen"}},
        Date:   time.Now(),
    }
    fmt.Printf("%v", w)
}

Looks good? Well, it works, but we can do better.










To avoid duplication, we can embed the Course struct into the Workshop struct:

type Workshop struct {
    Course
    Date time.Time
}

We simply remove the identifier Course and keep the type to embed it.


Is it extending the Course struct? No, under the hood it copies the fields from Course into Workshop.










A downside of using embedding is that fields cannot be set directly when creating an instance of the Workshop struct.

func main() {
    var w = Workshop{
        Name: "Go", // Error: unknown field 'Name' in struct literal
        Instructor: Instructor{FirstName: "Lasse", LastName: "Jensen"}, // Error: unknown field 'Instructor' in struct literal
        Date: time.Now(),
    }
    fmt.Printf("%v", w)
}

To set the fields, we need to use the Course type:

func main() {
    var w = Workshop{
        Course: Course{Name: "Go", Instructor: Instructor{FirstName: "Lasse", LastName: "Jensen"}},
        Date:   time.Now(),
    }
    fmt.Printf("%v", w)
}









One way to make this look nicer is to use the factory pattern:

func NewWorkshop(courseName string, instructor Instructor, date time.Time) Workshop {
    return Workshop{
        Course: Course{Name: courseName, Instructor: instructor},
        Date:   date,
    }
}









Order of properties

What happens if we have the same field in both the Workshop and Course structs?


type Workshop struct {
    Course
    Date time.Time
    Name string // Error: duplicate field 'Name' ???
}

Will we get an error? No, Go will use the field from the Workshop struct as it is the "closest".










We can still set the name of the Course.Name field, but we need to be explicit:


w.Name = "Go workshop"

w.Course.Name = "Go course"

w.Course.Name is also called an embedding property.










Sharing of methods

When you embed a struct, you also get access to its methods. Neat!