Structs & Pointers in Go

Structs in Go are one of the most powerful and widely used features. They allow you to group related data together, making your code cleaner and more organized. In this blog, we’ll explore how to use structs, anonymous structs, and embedded structs with easy-to-understand examples.


What is a Struct in Go?

A struct is like a container that holds multiple pieces of related data together. For example, if you want to represent a car, you might want to include details like its model, the radius of its wheels, and the material of the wheels. A struct can group these details together.

Here’s a simple example of a struct:

type Wheel struct {
    radius   int
    material string
}

type Car struct {
    Model string
    Wheel Wheel
}
  • Wheel is a struct that has radius and material.
  • Car is a struct that has a Model and a Wheel (which itself is a struct).

How to Use Structs?

To use a struct, you need to create an instance of it and provide values for its fields. Let’s look at an example:

car := Car{
    Model: "BMW",
    Wheel: Wheel{
        radius:   4,
        material: "Fibre",
    },
}
fmt.Println(car)

Output:

{BMW {4 Fibre}}

Here, we:

  1. Created a Car instance named car.
  2. Gave it a Model value of "BMW".
  3. Set the Wheel with radius as 4 and material as "Fibre".

What is an Anonymous Struct?

An anonymous struct is a struct without a name. You can define it directly inside another struct or inline where needed.

Here’s an example of an anonymous struct inside another struct:

type AnonymousCar struct {
    Model string
    Wheel struct { // Anonymous struct
        radius   int
        material string
    }
}

To initialize it:

anonymousCar := AnonymousCar{
    Model: "BMW",
    Wheel: struct {
        radius   int
        material string
    }{
        radius:   5,
        material: "Fibre2",
    },
}
fmt.Println(anonymousCar)

Output:

{BMW {5 Fibre2}}

Notice that for the Wheel field, we had to explicitly define the anonymous struct again when initializing it.


What is an Embedded Struct?

An embedded struct is a struct included directly in another struct. It allows you to use its fields as if they belong to the outer struct, making your code simpler.

Here’s an example:

type EmbeddedCar struct {
    Model string
    Wheel // Embedded struct
}

You can initialize it like this:

embeddedCar := EmbeddedCar{
    Model: "BMW",
    Wheel: Wheel{
        radius:   6,
        material: "Fibre2",
    },
}
fmt.Println(embeddedCar)

Output:

{BMW {6 Fibre2}}

How is an Embedded Struct Different?

In an embedded struct:

  1. The fields of the inner struct (Wheel) become part of the outer struct (EmbeddedCar).
  2. You can access these fields directly:
fmt.Println(embeddedCar.radius)   // Outputs: 6
fmt.Println(embeddedCar.material) // Outputs: Fibre2

This is more convenient than using an anonymous struct or nesting structs without embedding.


Complete Example Code

Here’s the full code combining all the concepts we discussed:

package main

import "fmt"

type Wheel struct {
    radius   int
    material string
}

type Car struct {
    Model string
    Wheel Wheel
}

type AnonymousCar struct {
    Model string
    Wheel struct {
        radius   int
        material string
    }
}

type EmbeddedCar struct {
    Model string
    Wheel
}

func main() {
    car := Car{
        Model: "BMW",
        Wheel: Wheel{
            radius:   4,
            material: "Fibre",
        },
    }

    anonymousCar := AnonymousCar{
        Model: "BMW",
        Wheel: struct {
            radius   int
            material string
        }{
            radius:   5,
            material: "Fibre2",
        },
    }

    embeddedCar := EmbeddedCar{
        Model: "BMW",
        Wheel: Wheel{
            radius:   6,
            material: "Fibre2",
        },
    }

    fmt.Println(car)
    fmt.Println(anonymousCar)
    fmt.Println(embeddedCar)
}

Output:

{BMW {4 Fibre}}
{BMW {5 Fibre2}}
{BMW {6 Fibre2}}

Key Takeaways for Beginners

  1. Named Structs: Use them when you have reusable types (like Wheel).
  2. Anonymous Structs: Use them when you need temporary or one-time-use types.
  3. Embedded Structs: Use them to simplify access to inner struct fields and avoid repetitive code.

By mastering these concepts, you can write cleaner and more organized code in Go!