DEV Community

loading...

How to Use Embedding to Write Cleaner Code in Go?

#go
Mohammad Aziz
I write bugs πŸ›
Originally published at iaziz786.com ・2 min read

Abstract

Go is cleaner because it doesn't support many of the features that tradition OO languages support. Less is more. Inheritance is one of those features but Go has a different style which can fulfil the necessity of inheritance. It's called Embedding.

Table of content

  • What is embedding
  • How to create embedding
  • Embedding In Interface
  • Embedding In Struct
  • Conclusion
  • Reference

What is embedding

You can "borrow" the functionality of a struct or interface into an another struct and interface respectively is called embedding. You can not embed an interface into a struct or vice versa.

How to create embedding

To create an embedding you need to put a different struct or interface into a different one without naming the field.

type Morning struct {
  breakfast bool
}

type Routine struct {
  Morning // ⬅️ no field name makes it embedded 
}

type Director interface {
  Direct()
}

type Producer interface {
  Produce()
}

type Creator interface {
  Director
  Producer
}
Enter fullscreen mode Exit fullscreen mode

Embedding In Interface

Interface when embedded is the union of all the methods present in all of the interfaces combined. If method Eat() is present on an interface and Sleep() on another then embedding them into an interface with Repeat() method will have all, Eat(), Sleep(), and Repeat() methods.

Embedding In Struct

Embedding in a struct is where you can see the real power of Go. Not only the fields that defined type has but also the methods you can access them directly. How cool is that! Let's continue with our Routine struct.

type Morning struct {
  breakfast bool
}

func (m Morning) hasBreakfast() bool {
  return m.breakfast
}

type Routine struct {
  Morning
}

r := Routine{}

r.hasBreakfast() // false
Enter fullscreen mode Exit fullscreen mode

You also the embedded type will be a field name on the struct. For example, you can have:

type DailySports struct {
  Jog            // field name Jog
  *Swim          // field name Swim
  sports.Cycling // field name Cycling
  *sports.Tennis // field name Tennis
}

func (d DailySports) enrolledBySwimming() bool {
  return d.Swim.Speed
}
Enter fullscreen mode Exit fullscreen mode

But you cannot have conflict while embedding. This makes sense otherwise you won't know which one to pick.

struct {
  *Swim         // β›” Now allowed
  *sports.Swim  // β›” Not allowed
}
Enter fullscreen mode Exit fullscreen mode

You can do all the things you can with the promoted fields but you can not use the field name present in the defined type while constructing the struct.

type Morning struct {
  breakfast bool
}

type Routine struct {
  Morning
}

r := Routine{breakfast: true} // β›” Not allowed
Enter fullscreen mode Exit fullscreen mode

Conclusion

You can use embedding to use any defined type to used inside a struct and borrow all the functionality it has. You need to check that the names don't clash otherwise you are good to go.

Reference

  1. https://golang.org/doc/effective_go.html#embedding
  2. https://golang.org/ref/spec#Struct_types

Discussion (0)