Type Embedding
In order to achieve composition, we need to take a look at type embedding in Go. Suppose we are trying to build a car. A car is composed of many small moving parts. We want to be able to reuse these small moving parts to build different type of cars.
Struct Embedding
First we have a turbo charged four cylinder engine.
type TurboCharged struct {
Horsepower int
Torque int
ChargerCount int
FanSpeed float64
}
We can define couple methods on the engine.
func (tc TurboCharged) ignite() {
fmt.Printf("4 cylinder is running, %d chargers are ready\n", tc.ChargerCount)
}
Now let's build a car with this turbo charged engine by embedding it into a car struct.
type Car struct {
TurboCharged
}
func (c Car) Start() {
c.ignite()
}
func main() {
c := Car{TurboCharged{300, 350, 2, 100.5}}
c.Start()
}
Output:
4 cylinder is running, 2 chargers are ready
Notice that ignite
is also embedded onto Car
. I made it private so that starting an engine is abstracted away from user.
Interface Embedding
Now you may ask, what if I want a different engine like a naturally aspirated 6 cylinder? You can achieve it by embedding interfaces.
type Engine interface {
ignite()
}
type NatAspirated struct {
Horsepower int
Torque int
}
func (na NatAspirated) ignite() {
fmt.Printf("6 cylinder is running, VROOOOMMMMM\n")
}
Change the embedded type to Engine
type Car struct {
Engine
}
func (c Car) Start() {
c.ignite()
}
Now we can put whatever engine we like into our car.
func main() {
var c Car
c = Car{NatAspirated{400, 450}}
// OR
c = Car{TurboCharged{300, 305, 2, 100.5}}
c.Start()
}
Last updated