golang embedded struct assignment

Embedding in Go: Part 1 - structs in structs

Go doesn't support inheritance in the classical sense; instead, in encourages composition as a way to extend the functionality of types. This is not a notion peculiar to Go. Composition over inheritance is a known principle of OOP and is featured in the very first chapter of the Design Patterns book.

Embedding is an important Go feature making composition more convenient and useful. While Go strives to be simple, embedding is one place where the essential complexity of the problem leaks somewhat. In this series of short posts, I want to cover the different kinds of embedding Go supports, and provide examples from real code (mostly the Go standard library).

There are three kinds of embedding in Go:

  • Structs in structs (this part)
  • Interfaces in interfaces ( part 2 )
  • Interfaces in structs ( part 3 )

Embedding structs in structs

We'll start with a simple example demonstrating the embedding of a struct in another struct:

Instances of Container will now have the field b as well. In the spec it's called a promoted field. We can access it just as we'd do for c :

When using a struct literal, however, we have to initialize the embedded struct as a whole, not its fields. Promoted fields cannot be used as field names in composite literals of the struct:

Note that the access co.b is a syntactic convenience; we can also do it more explicitly with co.Base.b .

Embedding structs also works well with methods. Suppose we have this method available for Base :

We can now invoke it on instances of Container , as if it had this method too:

To understand the mechanics of this call better, it helps to visualize Container having an explicit field of type Base and an explicit Describe method that forwards the call:

The effect of calling Describe on this alternative Container is similar to our original one which uses an embedding.

This example also demonstrates an important subtlety in how methods on embedded fields behave; when Base 's Describe is called, it's passed a Base receiver (the leftmost (...) in the method definition), regardless of which embedding struct it's called through. This is different from inheritance in other languages like Python and C++, where inherited methods get a reference to the subclass they are invoked through. This is a key way in which embedding in Go is different from classical inheritance.

Shadowing of embedded fields

What happens if the embedding struct has a field x and embeds a struct which also has a field x ? In this case, when accessing x through the embedding struct, we get the embedding struct's field; the embedded struct's x is shadowed .

Here's an example demonstrating this:

When used like this:

This prints:

Note that when accessing co.tag , we get the tag field of Container , not the one coming in through the shadowing of Base . We could access the other one explicitly, though, with co.Base.tag .

Example: sync.Mutex

The following examples are all from the Go standard library.

A classical example of struct-in-struct embedding in Go is sync.Mutex . Here's lruSessionCache from crypto/tls/common.go :

Note the embedding of sync.Mutex ; now if cache is an object of type lruSessionCache , we can simply call cache.Lock() and cache.Unlock() . This is useful in some scenarios, but not always. If the locking is part of the struct's public API, embedding the mutex is convenient and removes the need for explicit forwarding methods.

However, it could be that the lock is only used internally by the struct's methods and isn't exposed to its users. In this case I wouldn't embed the sync.Mutex , but would rather make it an unexported field (like mu sync.Mutex ).

I've written some more on embedded mutexes and gotchas to look out for here .

Example: elf.FileHeader

The embedding of sync.Mutex is a good demonstration of struct-in-struct embedding to gain new behavior. A different example involves an embedding for data. In debug/elf/file.go we find the structs that describe ELF files:

The elf package developers could have just listed all the header fields directly in File , but having it in a separate struct is a nice example of self-documenting data partitioning. User code may want to initialize and manipulate file headers separately from File , and the embedding design makes this natural.

A similar example can be found in compress/gzip/gunzip.go , where gzip.Reader embeds gzip.Header . This is a very nice example of embedding for data reuse because gzip.Writer also embeds gzip.Header , so this helps avoid copy-pasta.

Example: bufio.ReadWriter

Since an embedding struct "inherits" (but not in the classical sense, as described above) the methods of an embedded struct, embedding can be a useful tool to implement interfaces.

Consider the bufio package, which has the type bufio.Reader . A pointer to this type implements the io.Reader interface. The same applies to *bufio.Writer , which implements io.Writer . How can we create a bufio type that implements the io.ReadWriter interface?

Very easily with embedding:

This type inherits the methods of *bufio.Reader and *bufio.Writer , and thus implements io.ReadWriter . This is done without giving the fields explicit names (which they don't need) and without writing explicit forwarding methods.

A slightly more involved example is timerCtx in the context package:

To implement the Context interface, timerCtx embeds cancelCtx , which implements 3 of the 4 methods required ( Done , Err and Value ). It then implements the fourth method - Deadline on its own.

For comments, please send me an email .

IMAGES

  1. Structs in Go (Golang) : A Comprehensive Guide

    golang embedded struct assignment

  2. embedded struct golang

    golang embedded struct assignment

  3. Golang Tutorial Structs And Receiver Methods 2020 A Complete Guide To

    golang embedded struct assignment

  4. Structures In Golang

    golang embedded struct assignment

  5. Golang Project Structure [For Beginners]

    golang embedded struct assignment

  6. Golang Struct |去语言结构是如何工作的?

    golang embedded struct assignment

VIDEO

  1. GOLANG INTRO

  2. Day 3: SQL to Golang struct

  3. Golang: Struct, Methods, and Code Organization

  4. Did you know this about embedded interfaces in Go? #golang #shorts

  5. STOP Using JavaScript

  6. ITF10103 COO

COMMENTS

  1. Initialize embedded struct in Go

    type User struct { Email *string Username *string Password *string Name string } Of course, there is no need to store Email2 beyond registration. So I have two variables: req and u - …