All About Golang Struct ( Structs in Go language )

We have already seen Arrays, Slices, and maps. They all have a common limitation: they can store or process only one data type. But sometimes, we need to group various values ( an int, float, or a string ). And Go provides us with a way to do just that by using struct. Golang struct ( short for “structure” ) is a user-defined type that represents a collection of data fields. We can group different items into a single entity using struct.

In this post, we are going to learn about the Golang structs in detail.

Well, there are other topics regarding structs that we have covered in separate posts.

How to create a Golang struct

We can declare a struct by using the struct keyword, followed by the curly braces. And within the braces, we can define one or more fields the struct would contain. Each field definition consists of the field name, followed by its data type.

Syntax of declaring a struct
struct {
   field1 field1_DataType
   field2 field2_DataType
}

We can create our user-defined type using struct and then make the variables of that type. Below is the syntax for declaring a user-defined type.

type type_name struct {
   field1 field1_DataType
   field2 field2_DataType
}

So, if we want to create our user-defined type “Person”, then we can do it like this –

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

We can also place the fields of the same type in a single line.

type Person struct {
	firstName, lastName string
	age       int
	height    float64
}
user defined type using struct in golang

Now, we can also create variables of the type Person.

var person1 Person

Accessing and modifying a struct using the dot operator

We have created our struct, but how do we update its fields or access them in the Go language? This is where the dot operator( . ) will come to the rescue. Dot operator can be used for assigning values, updating, and retrieving them.

package main

import "fmt"

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

func main() {

	var person1 Person

	// assiging the values to the fields
	// of struct using dot operator
	person1.firstName = "codekru"
	person1.lastName = "website"
	person1.age = 22
	person1.height = 167.12

	fmt.Println("Person's age:", person1.age) // retrieving "age" using dot operator(.)

	person1.age = 30 // Updating the "age" value using "dot" operator(.)

	fmt.Println("Updated Person's age:", person1.age) // again retrieving "age" using dot operator(.)

}

Output –

Person's age: 22
Updated Person's age: 30

Accessing struct fields through pointers

How do we usually get the values stored at the pointer’s location? We use something like this.

func main() {
 
    var var1 int = 8
    var pointerToVar1 *int = &var1 
    fmt.Println("value at var1:", *pointerToVar1)
}

Then you might think we would use * with the struct as well, but that won’t work.

package main

import "fmt"

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

func main() {

	var person1 Person
	person1.age = 30

	var pointerToPerson *Person = &person1

	fmt.Println("Person's age:", *pointerToPerson.age)

}
invalid indirect of pointerToPerson.age (type int)

If we are writing *pointerToPerson.age, then Go thinks that age contains a pointer, but it doesn’t. To rectify this, we have to wrap the pointer within the parenthesis, and all would work fine.

package main

import "fmt"

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

func main() {

	var person1 Person
	person1.age = 30

	var pointerToPerson *Person = &person1

	fmt.Println("Person's age:", (*pointerToPerson).age)

}

Output –

Person's age: 30

Writing this syntax will become tedious at some point, so the dot operator (.) provides a very convenient way of accessing the fields of a struct through pointers.

Struct literals

Go provides us with the struct literals, which are similar to array literals for arrays, slice literals for slices, and map literals to work with maps. Go offers struct literal to let us create a struct and set its fields simultaneously and saves us from assigning the values one by one using the dot operator.

The syntax of a struct literal is almost similar to a map literal.

  • A struct literal starts with a struct type.
  • Then key/value pairs will be enclosed within the curly braces
  • For each pair, the key and the value will be separated by a colon ( : )
  • And multiple key-value pairs will be separated by the comma ( , )
person2 := Person{firstName: "Codekru", age: 22, height: 167.12, lastName: "website"}
package main

import "fmt"

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

func main() {

	person1 := Person{firstName: "Codekru", age: 22, height: 167.12, lastName: "website"}

	fmt.Println("Person's age:", person1.age)

}

Output –

Person's age: 22

Here, you might have noticed that the order of the field is different than what was specified during the declaration of the struct. We can specify the fields in any order while creating or defining structs using fields. Here, we have used the shorthand declaration to create a struct.

Without specifying fields

We can also set the fields of a struct without specifying the fields we are setting it for.

package main

import "fmt"

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

func main() {

	person1 := Person{"Codekru", "Website", 22, 167.12}

	fmt.Println("Person's age:", person1.age)

}

Output –

Person Details: {Codekru Website 22 167.12}

Here, the order of the fields should be the same as specified in the struct declaration.

How to export structs

We have to start the struct type name with a capital letter to export it outside of the package it’s defined in, and the same would also be the case for the struct fields. If we start the struct or its fields with the lowercase letters, then we won’t be able to use them outside of the package they are defined in.

Let’s make a package containing only the struct type and then use it elsewhere in other packages.

  • Create a new directory named “structs” inside the src folder of your workspace. For us, the src folder location is “C:\Program Files\Go\src
  • Create another directory called “codekru” inside the “structs
  • Now, create a codekru.go file that will contain the Person struct
|__src
   |
   |___structs
       |
       |___codekru
           |
           |___codekru.go

codekru.go file

package codekru

type Person struct {
	FirstName string  // exported field
	lastName  string  // unexported field
	Age       int     //exported field
	height    float64 // unexported field
}

To export the above struct, let’s create another file named “main.go” anywhere on the machine. Now, the Person struct should be prefixed with “codekru“, just like what we do with the fmt package and its functions ( fmt.Println() ).

main.go file

package main

import (
	"fmt"
	"structs/codekru"
)

func main() {

	var person1 codekru.Person
	person1.Age = 30

	fmt.Println("Person's age:", person1.Age)

}

Output –

Person's age: 30

Let’s try to access the unexported fields of the struct.

package main

import (
	"fmt"
	"structs/codekru"
)

func main() {

	var person1 codekru.Person
	person1.lastName = "website"

	fmt.Println("Person's lastname:", person1.lastName)

}

Output –

.\main.go:11:9: person1.lastNamee undefined (type codekru.Person has no field or method lastName)
.\main.go:13:43: person1.lastName undefined (cannot refer to unexported field or method lastName) 

We hope that you have liked the article. If you have any doubts or concerns, please feel free to write us in the comments or mail us at admin@codekru.com.

Related Articles

Liked the article? Share this on

Leave a Comment

Your email address will not be published. Required fields are marked *