Go Composition
In Go, composition refers to the structuring of data and behavior by combining multiple smaller types into a single, larger type. Composition in Go is achieved through embedding, which allows a struct to inherit the fields and methods of another struct. This allows for code reuse and modular design. With composition, complex types can be built from simpler components, promoting separation of concerns and making the code easier to understand and test.
Structs
The following example creates a struct called Pizza:
package mainimport "fmt"type Pizza struct {Name stringSize stringToppings []stringIsDelicious bool}
This structure can be used to create a new function that can help define what specific style of pizza is ordered.
This is done in the following example:
package mainimport "fmt"type Pizza struct {Name stringSize stringToppings []stringIsDelicious bool}func pizzaStyle(p Pizza) string {return p.Name + " pizza is a " + p.Size + " pizza with toppings of " + fmt.Sprint(p.Toppings)}func main() {myPizza := Pizza{Name: "Margherita",Size: "medium",Toppings: []string{"tomatoes", "mozzarella", "basil"},IsDelicious: true,}fmt.Println(pizzaStyle(myPizza))}
This example results in the following output:
Margherita pizza is a medium pizza with toppings of [tomatoes mozzarella basil]
A Struct Within a Struct
The following example has an important difference.
package mainimport "fmt"type Pizza struct {Name stringSize stringToppings []stringIsDelicious bool}func pizzaStyle(p Pizza) string {return p.Name + " pizza is a " + p.Size + " pizza with toppings of: " + fmt.Sprint(p.Toppings)}type Restaurant struct {Name stringRating intPizzaMenu []Pizza}func restaurantInfo(r Restaurant) string {return r.Name + " has a rating of " + fmt.Sprint(r.Rating) + " and serves the following pizzas: " + fmt.Sprint(r.PizzaMenu)}func main() {myPizza := Pizza{Name: "Margherita",Size: "medium",Toppings: []string{"tomatoes", "mozzarella", "basil"},IsDelicious: true,}myRestaurant := Restaurant{Name: "Pizzeria del Corso",Rating: 4,PizzaMenu: []Pizza{myPizza},}fmt.Println(pizzaStyle(myPizza))fmt.Println(restaurantInfo(myRestaurant))}
In this example Restaurant contains the Pizza structure.
The Pizza struct is defined with fields for the name, size, toppings, and whether or not it’s delicious. The pizzaStyle function takes a Pizza struct as an argument and returns a string that describes the pizza.
A struct named Restaurant is also defined that contains the Pizza structure, the restaurant name, and the restaurant rating. The restaurantInfo() function takes a Restaurant instance as an argument and returns a string that describes the restaurant.
In the main function, a Pizza struct called myPizza and a Restaurant struct called myRestaurant are created. Then, myPizza is passed to pizzaStyle() and myRestaurant is passed to restaurantInfo(), which are then printed to the console.
This example results in the following output:
Margherita pizza is a medium pizza with toppings of: [tomatoes mozzarella basil]Pizzeria del Corso has a rating of 4 and serves the following pizzas: [{Margherita medium [tomatoes mozzarella basil] true}]
Inheritance through Composition
A struct can ‘inherit’ the fields and methods of an embedded struct through composition rather than traditional inheritance. This type of inheritance is achieved with the following syntax:
type Embedded struct {
field string
}
func (a Embedded) printField() string {
return a.field
}
type MainStruct struct {
Embedded
}
func PrintEmbedded(m MainStruct) string {
return m.printField()
}
Consider the following addition to the pizza example:
type Address struct {Street stringCity stringCountry string}func (a Address) printAddress() string {return a.Street + ", " + a.City}type Restaurant struct {Name stringRating intPizzaMenu []PizzaAddress}func restaurantInfo(r Restaurant) string {return r.Name + ", located at " + r.printAddress() + ", " + r.Country + " has a rating of " + fmt.Sprint(r.Rating) + " and serves the following pizzas: " + fmt.Sprint(r.PizzaMenu)}
An Address struct is created, and a printAddress() method takes an Address as its receiver. The anonymous field Address is added to Restaurant which allows access to the Address fields and methods.
The restaurantInfo() function can now access the printAddress() method with r.printAddress() and the Country field with r.Country.
The following example adds the Address struct and method:
package mainimport "fmt"// ... Above Struct and Method declarationsfunc main() {myPizza := Pizza{Name: "Margherita",Size: "medium",Toppings: []string{"tomatoes", "mozzarella", "basil"},IsDelicious: true,}myAddress := Address{Street: "1st Avenue",City: "New York",Country: "USA",}myRestaurant := Restaurant{Name: "Pizzeria del Corso",Rating: 4,PizzaMenu: []Pizza{myPizza},Address: myAddress,}fmt.Println(pizzaStyle(myPizza))fmt.Println(restaurantInfo(myRestaurant))}
This example results in the following output:
Margherita pizza is a medium pizza with toppings of: [tomatoes mozzarella basil]Pizzeria del Corso, located at 1st Avenue, New York, USA has a rating of 4 and serves the following pizzas: [{Margherita medium [tomatoes mozzarella basil] true}]
Benefits Of Using Composition
Composition is a very strong technique for making complex structures and objects as a developer. Problems are broken down into smaller parts, and then managed in a structured way.
When designing software, it’s important to consider the composition of the components created and how they fit together to form a larger system. By adopting a compositional approach, software is created that is flexible, scalable, and easy to maintain over time.
Contribute to Docs
- Learn more about how to get involved.
- Edit this page on GitHub to fix an error or make an improvement.
- Submit feedback to let us know how we can improve Docs.
Learn Go on Codecademy
- Looking for an introduction to the theory behind programming? Master Python while learning data structures, algorithms, and more!
- Includes 6 Courses
- With Professional Certification
- Beginner Friendly.75 hours
- Learn how to use Go (Golang), an open-source programming language supported by Google!
- Beginner Friendly.6 hours