Golang structs

Structs

Structs in Golang are a compound data type that group different fields under the same name. They are similar to structs in C and to classes in oriented object languages.

Defining a struct

A struct can be defined using the key word type followed by the struct’s name and a list of fields inside struct {}

package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {
	var p Person
	p.Name = "Goku"
	p.Age = 5
	fmt.Println(p)
}
>>>>>
{Goku 5}

There are several ways to initialize a struct, here are some ways you can do this.

Field by Field

Assigning fields one at a time, like this:

package main

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{}
	p.Name = "Goku"
	p.Age = 5
}

Positional Values

Using positional values, respecting the order of the fields

package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{"Goku", 5}
	fmt.Println(p)
}

Named values

Using named values:

package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{Name: "Goku", Age: 5}
	fmt.Println(p)
}

Pointers

Using pointers is a very common way for functions to return a new struct.

package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {
	p := &Person{Name: "Goku", Age: 5}
	fmt.Println(p)
}

Optional Fields

If a field isn’t initializated, it will be assigned to the zero value for that kind of field.

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{}
	fmt.Println(p.Name)
	fmt.Println(p.Age)
}

Methods in structs

Although there are no classes in Go, we can define methods by associating functions to the struct.

Value Receiver

Methods with value receiver:

package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{"Goku", 5}
	p.Greetings("Hello")
}

func (p Person) Greetings(message string) {
	fmt.Printf("%s %s", message, p.Name)
}
>>>>>
Hello Goku

As p is assigned by value, any changes you make to p in the method will not be reflected in the original instance.

Pointer Receiver

As we are using a pointer receiver here, we can modify the instance value directly:

package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{"Goku", 5}
	p.IncrAge()
	fmt.Println(p.Age)
}

func (p *Person) IncrAge() {
	p.Age++
}
>>>>>
6

Anonymous fields

Go allows you to have a struct inside another struct (embedded structs)

package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

type Employee struct {
	Company string
	Person
}

func main() {
	p := Employee{
		Company: "Go",
		Person: Person{
			Name: "James",
			Age:  32,
		},
	}

	fmt.Println(p.Company)
	fmt.Println(p.Name)
	fmt.Println(p.Age)
}
>>>>>
Go
James
32

Struct comparison

We can compare structs using == and != operators, we can only do this when all of the structs’ fields are comparable. Examples of non-comparable fields include maps, slices and functions. Structs will be equal when all of the fields are equal.

package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {

	p1 := Person{"Goku", 5}
	p2 := Person{"Goku", 5}
	p3 := Person{"James", 32}

	fmt.Printf("%t\n", p1 == p2)
	fmt.Printf("%t\n", p1 == p3)

}
>>>>>
true
false

Conversion from Struct to Map

Although Go does not have a direct way to convert structs into maps, we can do this using packages like encoding/json, which serialize a struct into a JSON and then deserialize it into a map.

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func main() {

	p := Person{"Goku", 5}
	var m map[string]interface{}

	data, _ := json.Marshal(p)
	json.Unmarshal(data, &m)
	fmt.Println(m)

}
>>>>>
map[Age:5 Name:Goku]

Struct tags

In Go, tags are definied between backticks right after the struct field declaration. The convention is to use a list of key value pairs separated by spaces.

type Person struct {
	Name string `json:"name" xml:"Name"`
	Age  int    `json:"age" xml:"Age"`
}

Common use

Packages like encoding/json and encoding/xml, use struct tags to determine the field names in the data output. For example, in a serialization the encoder will use the name defined in the tag instead of the struct field name.