How to use struct in go lang?

This tutorial demonstrate you about struct and how we can efficiently use struct in go. How you can work with struct in go in simple way.

Struct:

struct is a user-defined type that contains a collection different or same type of fields. It is used to group related data to form a single unit. A Go struct can be compared to a lightweight class without the inheritance capabilities. Struct is help us to create complex data type by combining primitive datatypes.

Syntax:-

type <name of struct> struct {
    field1 type
    field2 type
       .
       .
       .
}

Example:

type Employee struct {
    name       string
    department string
    age        int
}

In the above example a new type is created as a Employee using type keyword. The struct keyword indicate to create struct followed by unique name and in the curly brackets the fields which belongs to that struct.

The struct is defined using the type keyword.

Initialise struct:

Now you know how to create or define the struct but to initialise the struct we do. Let us initialise the struct using shorthand assignment.

e := Employee{"Ram", "Operation", 42}

A new Employee created, whose name is Ram and he is from the Operation Department. The struct is initialized with the values which are provided in curly brackets. If you are providing only values in the curly brackets then you should maintain the order.

e := Employee{
      name: "Ram",
      deparment: "Operation",
      age: 42
   }

If in case you are providing values along with name then order is not require.

Example:

package main

import "fmt"
// employee struct
type Employee struct {
    name       string
    department string
    age        int
}

func main() {

    e := Employee{"Ram", "Operation", 42}

    fmt.Printf("%s is %d years old and he is  part of a %s department\n", e.name, e.age, e.department)
}

Defined Employee struct with three fields.

Output:-

$ go run structEx.go 
Ram is 42 years old and he is  part of a Operation department

Access struct fields:

You can access struct fields using dot(.) operator. As you have seen in above example, while displaying result on console in fmt.Printf() we used dot (.) operator.

package main

import "fmt"

type Employee struct {
    name       string
    department string
    age        int
}

func main() {

	e := Employee{"Ram", "Operation", 42}
	
	//empty assignment
	e1 := Employee{}
	e1.name="Rocky"
	e1.department="IT"
	e1.age=28


	fmt.Printf("%s is %d years old and he is  part of a %s department\n", e.name, e.age, e.department)
	fmt.Println("\n Dot Operator assigment result\n")
	fmt.Printf("%s is %d years old and he is  part of a %s department\n", e1.name, e1.age, e1.department)
}

Output:

$ go run structEx.go 
Ram is 42 years old and he is  part of a Operation department

 Dot Operator assigment result

Rocky is 28 years old and he is  part of a IT department

Here we have created e1 employee with empty initialisation and later assed fields using dot operator and do the assignment.

Anonymous struct:

We have an anonymous function the same way go also supports an anonymous struct. Anonymous struct Is a nameless struct and they are created only once. Let us create an anonymous struct:

package main

import "fmt"

func main() {

    e := struct {
		name       string
		department string
		age        int
    }{
        name: "Ram",
        department: "Operation",
        age: 42,
    }

    fmt.Printf("%s is %d years old and he is  part of a %s department\n", e.name, e.age, e.department)
}

Output:

$ go run anonymousstruct.go 
Ram is 42 years old and he is  part of a Operation department

The declaration of the struct is followed by its initialisation. Anonymous struct also created using struct keyword.

Nested struct in Go:

Struct within another struct is called a nested struct and go supports nested struct. We can access nested struct fields using the dot(.) operator only. You can access inner struct fields using dot operator, first access inner struct and then access inner struct fields

package main

import "fmt"

type Address struct {
    city    string
	state string
	pincode string
}

type Employee struct {
    name    string
    age     int
    address Address
}

func main() {

    e := Employee{
        name: "Mahesh",
        age:  24,
        address: Address{
            city:    "Pune",
			state: "India",
			pincode: "413310",
        },
    }

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

Output:

$ go run nestedStruct.go 
Name: Mahesh
Age: 24
City: Pune
PinCode: 413310
State: India

Functions as a fields in struct:

Go support defining function as struct fields. The way we define or use primitive data type in struct same way go support function as struct fields.

Example:

package main

import "fmt"

type Info func(string, string, int) string

type Employee struct {
    name       string
    department string
    age        int
    info       Info
}

func main() {

    e := Employee{
        name:       "Maheshwar",
        department: "IT",
        age:        41,
        info: func(name string, department string, age int) string {

            return fmt.Sprintf("%s is %d years old and he is  part of a %s department\n", name, age, department)
        },
    }

    fmt.Printf(e.info(e.name, e.department, e.age))
}

In this example we have Employee struct with info function.

Output:

$ go run functionAsStructField.go 
Maheshwar is 41 years old and he is  part of a IT department

Pointers to struct:

Pointers are the special variable which stores the memory address. Go support pointers to strut, a pointer to struct can be created using & operator and dereference using * operator. Pointer to struct behave same like normal pointer variable.

Example:

package main

import "fmt"

type Circle struct {
    redius int
    circum int
}

func main() {

    c := Circle{3, 4}

    c_p := &c

    (*c_p).redius = 1
    c_p.circum = 2

    fmt.Println(c)
}

Output:-

$ go run structpointer.go 
{1 2}

In this example, we have created normal variable c and pointer for that variable c_p:=&c.

Another way you can create pointer to struct using new keyword.

 c := new(Circle)

In this example new keyword create new pointer to the Circle struct.

Constructors in GO:-

GO is doesn’t have built-in support for the constructor. The accepted best practice is to write zero or more constructors for your types. If you are familiar with any OOP then you know that constructor is a special function whose name is the same as a class name, it executed at the time of object creation.

Example:

package main

import "fmt"

type Employee struct {
    name       string
    department string
    age        int
}

func newEmployee(name string, department string, age int) *Employee {

    ptr := Employee{name, department, age}
    return &ptr
}

func main() {

    e := newEmployee("Mahesh", "IT", 29)

    fmt.Printf("%s is %d years old and he is  part of a %s department\n", e.name, e.age, e.department)
}

In this code we defined newEmployee as a constructor which takes three input parameter by using shorthand assignment we have created prt variable of Employee Struct.

Two best practices:

  1. Make the zero value of your struct a sensible default. (While this looks strange to most people coming from “traditional” oop it often works and is really convenient).
  2. Provide a function or if you have several such types in your package functions and so on.

Comparing structs in GO:

Two Go structs are equal if their corresponding fields are equal. Structs of the same type can be compared using comparison operator.

Exaple:

package main

import "fmt"

type Triangle struct {
    h int
	w int
	l int
}

func main() {

    t1 := Triangle{2, 3,4}
    t2 := Triangle{2, 3,4}

    if t1 == t2 {

        fmt.Println("The triangel structs are equal")
    } else {

        fmt.Println("The triangel structs are not equal")
    }
}

Output:

$ go run structcompare.go 
 The triangel structs are equal

Promoted fields in Struct:

Promoted fields in concept similar like inherited fields in OOP. The fields of a nested anonymous struct are promoted; that is, they are accessed without referring to the nested struct. In nested struct we have address struct in Employee struct and you are able to access the address struct fields from employee struct object.

Example:

The below code snippet, which you have seen in nested struct as well.

package main

import "fmt"

type Address struct {
    city    string
	state string
	pincode string
}

type Employee struct {
    name    string
    age     int
    address Address
}

func main() {

    e := Employee{
        name: "Mahesh",
        age:  24,
        address: Address{
            city:    "Pune",
			state: "India",
			pincode: "413310",
        },
    }

    fmt.Println("Name:", e.name)
    fmt.Println("Age:", e.age)
// the fields city, pincode and state are promoted fields
	fmt.Println("City:", e.address.city)
	fmt.Println("PinCode:", e.address.pincode)
    fmt.Println("State:", e.address.state)
}

The state, city and pincode are the promoted fields. They are accessed by direclty referring to its parent struct i.e Employee struct.

Export struct in go:

In Go, identifiers are exported to other packages if the name starts with an uppercase letter, otherwise, the accessibility will be limited within the package only. Named structs that start with a capital letter are exported and accessible from outside their packages. In the same fashion struct fields names started with capital letters are accessible from the outside. If a field or method starts with a lowercase letter, the member is unexported and does not have accessibility outside of the package.

To understand this we are creating one new module.

$ go mod init exportingstr

The above command creating go module as go.mod and content of that file is:

module exportingstr

go 1.15

Create two models

Employee.go, name of struct is starting with capital letter also Name field also capital letter, that means both are accessible outside the package.

package model

type Employee struct {
    Name       string
    department string
    age        int
}

Create Address struct, which is non accessible outside of package.

package model

type address struct {
    city    string
	state string
	pincode string
}
package main

import (
    "/exportingstr/model"
    "fmt"
)

func main() {

    e := model.Employee{Name: "Maheshwar"}

    fmt.Printf("Employee Name is %s", e.Name)
}

Exporting functionality is like defining scope for fields, method this also help programmer to implement abstraction and hiding logic.

Conclusion:

In this article, you learned about struct, some basic syntax also you are familiar with how you can use struct along with pointers and functions which is first class citizen of go language.

Source Code:

https://github.com/maheshwarLigade/spring-boot-examples
$ git clone https://github.com/maheshwarLigade/GoLanguage-tutorials
$ cd GoLanguage-tutorials
$ go run structcompare.go