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.