6 minutes read

Go has several data types that we use to group multiple elements, such as arrays and slices; however, they can't hold values of different data types at the same time! When we need to combine variables of different types in our Go program, structs are the data type we should implement.

In this topic, we'll learn about Go structs: how to declare and initialize them, how to access the data within them, and finally how to compare one struct with another.

What is a struct?

A struct, short for structure, is a data type that allows us to group and combine elements of different types such as integers, strings, maps, and even other structs into a single type. Any real-world entity that has a series of properties can be represented as a struct.

If you are familiar with Java or C++, structs can be compared with the classes in these object-oriented programming languages. Go's struct type can be termed as a lightweight class that does not support inheritance, but supports composition.

Now that we know the essence of the struct type, let's get into detail. To begin with, we will declare the Animal struct:

type Animal struct {
    Name        string
    Class       string
    Emoji       string
    avgLifespan int
    Domestic    bool
}

In this code snippet, the type keyword is used to introduce the new struct type; it is followed by the name of the structure Animal, and finally the keyword struct. After that, we define a list of various fields inside the curly braces {}, each field having a name and a type.

When declaring structs, we can also define different fields of the same data type in one line:

type Animal struct {
    Name, Class, Emoji string // define all 'string' types in one line
    avgLifespan        int    
    Domestic           bool
}

Initializing structs

Now that we've declared the Animal struct, we can initialize it with data and also access its fields. Let's look at different ways we can initialize our new Animal struct.

The most basic struct initialization looks like this:

var crocodile Animal

Like with other data types, this will create a local crocodile struct variable of the Animal type and all its fields will be set to their default values.

Another way to initialize a struct is with the help of the new function from Go's builtin package:

crocodile := new(Animal)

Here, the new function allocates memory for all the fields of the struct, sets them to their default value, and returns a pointer to the struct (*Animal).

Finally, we can also initialize a variable of a struct type by using a struct literal:

// Initializing 'crocodile' with a struct literal using the ':=' operator:
crocodile := Animal{Name: "Crocodile", Class: "Reptile", Emoji: "🐊", avgLifespan:55, Domestic: false}

fmt.Printf("%#v", crocodile) 
// main.Animal{Name:"Crocodile", Class:"Reptile", Emoji:"🐊", avgLifespan:55, Domestic:false}

Accessing and initializing individual fields

After initializing our struct with data, we can access its individual fields with the help of the . operator. Let's go ahead and access the fields of the previously initialized crocodile struct:

fmt.Println("Animal name:", crocodile.Name)
fmt.Println("Class:", crocodile.Class)
fmt.Println("Emoji representation:", crocodile.Emoji)
fmt.Println("Average lifespan in years:", crocodile.avgLifespan)
fmt.Println("Is this animal domestic?", crocodile.Domestic)

// Output:
// Animal name: Crocodile
// Class: Reptile
// Emoji representation: 🐊
// Average lifespan in years: 55
// Is this animal domestic? false

Apart from accessing individual fields that we have previously declared with a struct literal, we can also assign values to individual fields of an initialized struct, using the . operator. For example, let's initialize some of the fields of the new octopus struct of the Animal type:

var octopus Animal // declare & initialize a new 'octopus' struct of the 'Animal' type

octopus.Name = "Octopus"
octopus.Class = "Cephalopod"
octopus.Emoji = "🐙"
...

Structs comparison and equality

Two structs are comparable with the equality == operator if they belong to the same type and have the same field values. Below we will declare a new Person struct and implement some code to compare three different structs of the Person type:

type Person struct {
    Name string
    Age  int
}

// Declare and assign three different structs of the 'Person' type
jerry1 := Person{Name: "Jerry", Age: 37}
jerry2 := Person{Name: "Jerry", Age: 37}
jerry3 := Person{Name: "Jerry"} // 'jerry3' is missing initialization for the 'Age' field

fmt.Printf("structs: jerry1 and jerry2 are equal is %t\n", jerry1 == jerry2)
fmt.Printf("structs: jerry1 and jerry3 are equal is %t", jerry1 == jerry3)

// Output:
// structs: jerry1 and jerry2 are equal is true
// structs: jerry1 and jerry3 are equal is false

We can see that the structs jerry1, jerry2 and jerry3 all belong to the same Person type; however, jerry3 doesn't have the same field values as the other two. It is missing initialization for the Age field.

Since the Age field isn't initialized in the jerry3 struct, if we try comparing it with jerry1 we will find that they are not equal, because jerry1 has both Name and Age fields initialized, while jerry3 only has one initialized field: Name.

Take notice that struct type variables are not comparable if they contain fields such as maps or slices that can't be compared using the equality == operator.

Conclusion

Wow! This has been quite a dense topic, but we've learned a lot. The most important points of today's topic are:

  • What a struct is and how we can declare and initialize it in our Go program.

  • How to access or assign the data of an individual struct field.

  • How to compare one struct with another and check for equality or inequality.

We're not done yet! Let's apply our recently acquired knowledge about structs to solve some problems.

63 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo