Golang Struct Embedding

Beginner

This tutorial is from open-source community. Access the source code

Introduction

This lab aims to test your understanding of struct embedding in Golang. You will be required to create a struct that embeds another struct and access its fields and methods.

Struct Embedding

Create a struct named container that embeds a struct named base. The base struct should have a field named num of type int and a method named describe() that returns a string. The container struct should have a field named str of type string. The container struct should be able to access the num field and describe() method of the base struct.

  • The base struct should have a field named num of type int.
  • The base struct should have a method named describe() that returns a string.
  • The container struct should have a field named str of type string.
  • The container struct should embed the base struct.
  • The container struct should be able to access the num field and describe() method of the base struct.
$ go run struct-embedding.go
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

There is the full code below:

// Go supports _embedding_ of structs and interfaces
// to express a more seamless _composition_ of types.
// This is not to be confused with [`//go:embed`](embed-directive) which is
// a go directive introduced in Go version 1.16+ to embed
// files and folders into the application binary.

package main

import "fmt"

type base struct {
    num int
}

func (b base) describe() string {
    return fmt.Sprintf("base with num=%v", b.num)
}

// A `container` _embeds_ a `base`. An embedding looks
// like a field without a name.
type container struct {
    base
    str string
}

func main() {

    // When creating structs with literals, we have to
    // initialize the embedding explicitly; here the
    // embedded type serves as the field name.
    co := container{
        base: base{
            num: 1,
        },
        str: "some name",
    }

    // We can access the base's fields directly on `co`,
    // e.g. `co.num`.
    fmt.Printf("co={num: %v, str: %v}\n", co.num, co.str)

    // Alternatively, we can spell out the full path using
    // the embedded type name.
    fmt.Println("also num:", co.base.num)

    // Since `container` embeds `base`, the methods of
    // `base` also become methods of a `container`. Here
    // we invoke a method that was embedded from `base`
    // directly on `co`.
    fmt.Println("describe:", co.describe())

    type describer interface {
        describe() string
    }

    // Embedding structs with methods may be used to bestow
    // interface implementations onto other structs. Here
    // we see that a `container` now implements the
    // `describer` interface because it embeds `base`.
    var d describer = co
    fmt.Println("describer:", d.describe())
}

Summary

In this lab, you learned how to embed a struct in another struct and access its fields and methods. You also learned how to bestow interface implementations onto other structs using struct embedding.