Structs in Golang are one of the most used and a way to create user-defined types.

In this, I will be covering all the basics about structs and how to use them in your go programs with a couple of examples.

Let’s get started!

Introduction

A struct is a collection of multiple data fields with their defined data types grouped together. They are useful for grouping data together to form custom records. A struct consists of both built-in and user-defined types (struct itself is a user-defined type).

Structs in Golang are mutable i.e they can be modified throughout the program.

Structs help in improving the overall code quality by allowing us to create and pass complex data structures across multiple modules. Imagine passing 10 parameters into a function, you’ll soon run away from code. This is exactly why structs are useful, now instead of 10 parameters you simply pass a single struct to that function.

A struct is declared using two keywords – type and struct. It is wrapped with curly brackets (just like classes in java) – which contains a set of fields that have a defined type and an identifier(name). We discuss the implementation details in the next section.

If you come from an Object-oriented Programming(OOP) background, you can think of struct as a class but without inheritance.

Declaring structs

Now, that you understand what a struct is and why it is used, it’s time to learn how to declare structs. The basic skeleton of a struct looks like –

type name_of_struct struct { 
     field1 data_type_field1 
     field2 data_type_field2 
 }

Here, type and struct are keywords, whereas the struct contains multiple fields with their defined datatype.

Let’s see an example –

package main

import (
	"fmt"
)

type User struct {
	name        string
	age         int
	bankBalance float32
}

func main() {
	var user User
	fmt.Println(user)
}

Here, we define a User struct which consists of  string, int and float32 fields. In the main() we declare our struct as user and print it! The output we get is zero/empty value of struct since we haven’t initialized it yet! The zero value is basically zero values of each field.

{ 0 0}

Initializing structs

In the previous section, we learned how to declare structs. Now, we would want to initialize or assign them values. Check the code below on how we do that –

package main

import (
	"fmt"
)

type User struct {
	name        string
	age         int
	bankBalance float32
}

func main() {
	// With field names
	user1 := User{
		name:        "Mohit",
		age:         24,
		bankBalance: 100.0,
	}
	
	// Without field names
	user2 := User{"Nidhi", 21, 1000.0}
	
	fmt.Println(user1)
	fmt.Println(user2)
}

The code itself explains how we initialize two structs with and without field names. Here, the output will be –

{Mohit 24 100}
 {Nidhi 21 1000}

In the above case, if one of the fields is not initialized, then that field defaults to its zero value.

user1 := User{
	name:        "Mohit",
	age:         24,
}

 // Output - { Mohit 24 0.0 }

There is one more way to create structs using new keyword. We will look at how to use it in the next section.

Accessing fields of a struct

Now we know how to create and initialize structs, let’s see how to access the fields of a struct. For this, Golang provides us with the dot operator. Continuing with the previous example, let’s access name and age fields and print them.

package main

import (
	"fmt"
)

type User struct {
	name        string
	age         int
	bankBalance float32
}

func main() {
	// With field names
	user := User{
		name:        "Mohit",
		age:         24,
		bankBalance: 100.0,
	}

	fmt.Println(user.name)
	fmt.Println(user.age)
	fmt.Println(user.bankBalance)
}

Here, we use struct_name.field_name to access fields in a struct. The output of the above code will be –

Mohit
 24
 100

As mentioned earlier, we can create structs with new keyword. Let’s see how –

user := new(User)
 user.name = "Mohit"
 user.age = 24
 user.bankBalance = 100.0

 fmt.Println(user)

 // Output - &{Mohit 24 100}

The new keyword returns the pointer to the initialized struct. In Golang you don’t need to explicitly dereference the pointer but fmt.Println(*user) would result in the same output.

Nested structs

Structs in golang can contain other user-defined types as well. So, a struct can contain other nested structs.

package main

import (
	"fmt"
)

type User struct {
	name        string
	age         int
	bankBalance float32
	roleDetails RoleDetails
}

type RoleDetails struct {
	position string
	team     string
}

func main() {
	roleDetailForMohit := RoleDetails{
		position: "Software Engineer",
		team:     "Transport",
	}
	user := User{
		name:        "Mohit",
		age:         24,
		bankBalance: 100.0,
		roleDetails: roleDetailForMohit,
	}

	fmt.Println(user)
}

In the code above, we have RoleDetails struct as a part of User struct. The output will be –

{Mohit 24 100 {Software Engineer Transport}}

If you want to access roleDetails, you can do that using the same dot operator –

user.roleDetails.position

Struct Equality

Two structs are equal if each of the fields they have are equal (both built-in and user-defined) but not all datatypes are comparable. (map is not comparable directly). Let’s see an example to demonstrate equality.

package main

import (
	"fmt"
)

type User struct {
	name        string
	age         int
	bankBalance float32
}

func main() {
	user1 := User{
		name:        "Mohit",
		age:         24,
		bankBalance: 100.0,
	}
	user2 := User{
		name:        "Mohit",
		age:         24,
		bankBalance: 100.0,
	}
	user3 := User{
		name:        "Nidhi",
		age:         21,
		bankBalance: 1000.0,
	}

	if user1 == user2 {
		fmt.Println("user1 and user2 are equal")
	} else {
		fmt.Println("user1 and user2 are not equal")
	}

	if user1 == user3 {
		fmt.Println("user1 and user3 are equal")
	} else {
		fmt.Println("user1 and user3 are not equal")
	}
}

Empty and zero value structs are equal. Order of fields doesn’t matter, basically, each field should match for equality. Output for code above will be –

user1 and user2 are equal
user1 and user3 are not equal

Conclusion

Awesome!

Now you are ready to use structs in golang. We covered all the basics like declaration, initialization, and accessing struct fields. We also looked at how to compare two structs and even implemented a nested struct. Here are some resources to learn more about structs –

There is a lot more to learn about structs, but it’s a good start for now. I hope you learned something new!

Keep exploring. Keep learning!