“How To Use Structs In Golang?”

golang
Reading Time: 4 minutes

What is a struct?

A struct is a user-defined type that represents a collection of fields. It can be used in places where it makes sense to group the data into a single unit rather than having each of them as separate values. A structure is used mainly when you need to define a schema made of different individual fields properties). Like a class, we can create an object from this schema (class is analogous to the schema). Structs can improve modularity and allow to create and pass complex data structures around the system.

Declaring a struct type

We will see how we can declare an struct and how to use struct. We use struct keyword to create a new structure type as shown in the example below.

	type <name-of-custom-type> struct {
		field1-Name field1-Type
		field2-Name field2-Type
		...
	}

In the above syntax, <name-of-custom-type> is a struct type while field1-Name and field1-Name are fields of data type field1-Type and field1-Type respectively.

Take a look at this example to understand how you can implement a custom data type using the above syntax.

package main

import "fmt"

func main() {
    type Employee struct {
        firstname string
        lastname string
        age int
        job string
        salary int
    }

    emp1:= Employee {
        firstname: "Abhishek",
        lastname: "Verma",
        age: 35,
        job: "Devops Engineer",
        salary: 5000,
    }

    fmt.Println(emp1)
}

You can also define different fields of the same data type in the same line.

     type Employee struct {
        firstname, lastname, job string
        age, salary int
    }

When a struct is defined and it is not explicitly initialised with any value, the fields of the struct are assigned their zero values by default.

Zero value of a struct

package main

import (  
    "fmt"
)

type Employee struct {  
        firstname string
        lastname string
        age int
        salary int
}

func main() {  
    var emp Employee
    fmt.Println("First Name:", emp.firstname)
    fmt.Println("Last Name:", emp.lastname)
    fmt.Println("Age:", emp.age)
    fmt.Println("Salary:", emp.salary)
}

The above program defines emp but it is not initialized with any value. Hence firstname and lastname are assigned the zero values of string which is an empty string “” and age, salary are assigned the zero values of int which is 0. This program prints:

First Name:  
Last Name:  
Age: 0  
Salary: 0  

Anonymous struct

An anonymous struct is a struct with no explicitly defined derived struct type. So far, we have created Employee struct type which emp1 infers. But in case of an anonymous struct, we do not define any derived struct type and we create a struct by defining the inline struct type and initial values of the struct fields in the same syntax.

package main

import "fmt"

func main() {
	emp1 := struct {
        firstname string
        lastname string
        age int
        job string
        salary int
    }{
        firstname: "Abhishek",
        lastname: "Verma",
        age: 35,
        job: "Devops Engineer",
        salary: 5000,
    }
	fmt.Println(emp1)
}

Structs and Composite Type Fields

A struct can contain a composite data type as a field. Here is a Student struct that has a slice for storing test grades

type Student struct {
  name string
  major string
  grades []int
}
func main() {
  var st1 Student
  st1.name = "Jane Doe"
  st1.major = "History"
  st1.grades = append(st1.grades, 81)
  st1.grades = append(st1.grades, 93)
  st1.grades = append(st1.grades, 88)
  fmt.Println(st1)
}

You can also create a Student object using a struct literal, even with the slice, like this:

st1 := Student{"Jane Doe", "History", []int {81, 90, 88}}

Besides having a composite type such as a slice be a field, structs can have other structs as part of their fields. Here is an example of a Line struct that has two Point structs as its fields:

type Point struct {
  x, y int
}
type Line struct {
  p1 Point
  p2 Point
}
func main() {
  var line1 Line
  line1.p1.x = 3
  line1.p1.y = 4
  line1.p2.x = 5
  line1.p2.y = 8
  fmt.Println(line1)
}

Nested structs

It is possible that a struct contains a field which in turn is a struct. These kinds of structs are called nested structs. Nesting one struct within another can be a useful way to model more complex structures.

package main

import (  
    "fmt"
)

type Address struct {  
    city  string
    state string
}

type Person struct {  
    name    string
    age     int
    address Address
}

func main() {  
    p := Person{
        name: "Naveen",
        age:  50,
        address: Address{
            city:  "Bangalore",
            state: "Karnataka",
        },
    }

    fmt.Println("Name:", p.name)
    fmt.Println("Age:", p.age)
    fmt.Println("City:", p.address.city)
    fmt.Println("State:", p.address.state)
}

The Person struct in the above program has a field address which in turn is a struct. This program prints

Name: Naveen
Age: 50
City: Bangalore
State: Karnataka

Promoted fields

Fields that belong to an anonymous struct field in a struct are called promoted fields since they can be accessed as if they belong to the struct which holds the anonymous struct field. Let’s dive right into some code to understand this

package main

import (  
    "fmt"
)

type Address struct {  
    city  string
    state string
}
type Person struct {  
    name string
    age  int
    Address
}

func main() {  
    p := Person{
        name: "Naveen",
        age:  50,
        Address: Address{
            city:  "Chicago",
            state: "Illinois",
        },
    }
    fmt.Println("Name:", p.name)
    fmt.Println("Age:", p.age)
    fmt.Println("City:", p.city)   
    fmt.Println("State:", p.state)
    } 

But the cool thing about Go is that, when we use an anonymous nested struct, all the nested struct fields are automatically available on parent struct. This is called field promotion.

In the above program, all fields of the anonymously nested struct Address has been promoted to parent struct Person and we can access these fields as if they were defined on the Person struct.

Pointer to a struct

Pointers are a useful entity that stores a memory address in it. When we want to manipulate something via its address, we are doing it in the most efficient way. Instead of taking a copy of it, we are changing the original value itself. It is also possible to create pointers to a struct in Go.

package main

import (  
    "fmt"
)

type Employee struct {  
    firstName string
    lastName  string
    age       int
    salary    int
}

func main() {  
    emp8 := &Employee{
        firstName: "Sam",
        lastName:  "Anderson",
        age:       55,
        salary:    6000,
    }
    fmt.Println("First Name:", (*emp8).firstName)
    fmt.Println("Age:", (*emp8).age)

Why to Use Structs

The most obvious reason for why you would want to use a struct is when you have a data type that consists of more than one field.

The first reason is that structs provide clarity on data relationships. When you are keeping track of geometric points, it makes sense to have a single entity that has x and y fields rather than individual x and y points that can’t be related to one another.

The second reason is that structs simplify operations on blocks of data. If your program involves employee data, it makes more sense to keep all the employee data within one entity rather than having separate variables for each piece of data.

The final reason is that structs simplify function parameter lists by making them shorter. 

knoldus


Written by 

I am an DevOps engineer having experience working with the DevOps tool and technologies like Kubernetes, Docker, Ansible, AWS cloud, prometheus, grafana etc. Flexible towards new technologies and always willing to update skills and knowledge to increase productivity.