Home

Understanding Embedded Structs in Go: Composition and Inheritance

21 views

In Go, you can use embedded structs to create a form of inheritance or composition. This allows one struct to include another struct directly, inheriting its fields and methods. Embedded structs provide a way to compose complex types out of simpler ones and allow you to write more modular and reusable code.

Example: Basic Embedded Struct

package main

import (
	"fmt"
)

type Address struct {
	Street string
	City   string
	State  string
	ZipCode string
}

type Person struct {
	Name    string
	Age     int
	Address // Embedded struct
}

func main() {
	p := Person{
		Name: "John Doe",
		Age:  30,
		Address: Address{ // Initialize fields of the embedded struct
			Street: "123 Elm St",
			City:   "Somewhere",
			State:  "CA",
			ZipCode: "12345",
		},
	}

	// Access fields of the embedded struct directly
	fmt.Printf("Name: %s\n", p.Name)
	fmt.Printf("Age: %d\n", p.Age)
	fmt.Printf("Address: %s, %s, %s, %s\n", p.Street, p.City, p.State, p.ZipCode)
}

Example: Methods in Embedded Structs

You can also define methods on both the outer struct and the embedded struct:

package main

import (
	"fmt"
)

type Address struct {
	Street string
	City   string
	State  string
	ZipCode string
}

func (a Address) FullAddress() string {
	return fmt.Sprintf("%s, %s, %s, %s", a.Street, a.City, a.State, a.ZipCode)
}

type Person struct {
	Name    string
	Age     int
	Address // Embedded struct
}

func (p Person) FullDetails() string {
	return fmt.Sprintf("Name: %s, Age: %d, Address: %s", p.Name, p.Age, p.FullAddress())
}

func main() {
	p := Person{
		Name: "John Doe",
		Age:  30,
		Address: Address{ // Initialize fields of the embedded struct
			Street: "123 Elm St",
			City:   "Somewhere",
			State:  "CA",
			ZipCode: "12345",
		},
	}

	// Access methods of the embedded struct and the outer struct
	fmt.Println(p.FullDetails())
}

Example: Multiple Embedded Structs

A struct can embed multiple other structs. Here’s an example:

package main

import (
	"fmt"
)

type Address struct {
	Street string
	City   string
	State  string
	ZipCode string
}

type Contact struct {
	Email   string
	Phone   string
}

type Person struct {
	Name    string
	Age     int
	Address // Embedded struct
	Contact // Another embedded struct
}

func main() {
	p := Person{
		Name: "John Doe",
		Age:  30,
		Address: Address{ // Initialize fields of the embedded struct
			Street: "123 Elm St",
			City:   "Somewhere",
			State:  "CA",
			ZipCode: "12345",
		},
		Contact: Contact{
			Email: "john@example.com",
			Phone: "123-456-7890",
		},
	}

	// Access fields of the embedded structs directly
	fmt.Printf("Name: %s\n", p.Name)
	fmt.Printf("Age: %d\n", p.Age)
	fmt.Printf("Address: %s, %s, %s, %s\n", p.Street, p.City, p.State, p.ZipCode)
	fmt.Printf("Email: %s\n", p.Email)
	fmt.Printf("Phone: %s\n", p.Phone)
}

Explanation

  1. Basic Embedded Struct:

    • The Person struct includes Address as an embedded struct.
    • Fields of Address can be accessed directly as if they were fields of Person.
  2. Methods in Embedded Structs:

    • The Address struct has a FullAddress method.
    • The Person struct has a FullDetails method that calls the FullAddress method.
    • Both methods can be accessed directly on a Person instance.
  3. Multiple Embedded Structs:

    • The Person struct includes both Address and Contact as embedded structs.
    • Fields from both Address and Contact can be accessed directly on a Person instance.

Using embedded structs is an efficient way to modularize your code and promote reuse while maintaining a simple and intuitive syntax. It is a powerful feature in Go that combines the concepts of composition and inheritance.