Skip to content

Latest commit

 

History

History
158 lines (113 loc) · 3.19 KB

3.2.md

File metadata and controls

158 lines (113 loc) · 3.19 KB

Structs

Concepts

Structs help organize related data into a single entity.

Definition

Generally, structs are defined at the module level, and can be capitalized if they are to be exported:

package main

type item struct {
    name string
    price int
}

func main() {
    ...
}

name and price are referred to as fields of item.

Declaration / Assignment

Two ways to declare structs using zero-value initialization:

...

func main() {
    var waffle item
    dog := item{}
    fmt.Printf("%#+v\n%#+v\n", waffle, dog) // go doc fmt
}

There are two ways to declare a struct while initializing the fields of the struct:

...

func main() {
    teddyBear := item{"teddy", 2}
    fidgetSpinner := item{price: 2, name: "spinner"}

    ...
}

The first method doesn't use the field names, and the compiler implicitly knows that the field values are in order. If we include the field names, we can declare them in any order.

We can also get and set fields after struct declaration:

...

func main() {
    teddyBear := item{"teddy", 2}
    fmt.Println(teddyBear.price) // get
    teddyBear.price = 3 // set
    fmt.Println(teddyBear.price)
}

Nested structures are very common in go:

package main

import "fmt"

type node struct {
    value int
    next *node
}

func main() {
    n1 := node{100, nil}
    n2 := node{}
    n1.next = &n2
    fmt.Printf("%#+v\n%#+v\n", n1, n2)
}

We can also use structs in functions:

...

func main() {
    n1 := node{100, nil}
    n2 := node{}
    n2.value = 45
    n1.next = &n2
    fmt.Println(nodeAndChildSum(n1, 2))
}

func nodeAndChildSum(n node, extra int) int {
        return n.value + n.next.value + extra
}

Although this is valid go code, it is more common to capture struct related behavior in methods:

...

func main() {
    n1 := node{100, nil}
    n2 := node{45, nil}
    n1.next = &n2
    fmt.Println(n1.childSum(2))
}

func (n node) childSum(extra int) int {
    return n.value + n.next.value + extra
}

Here we can see childSum is defined on (n node), so now you can call x.childSum for any x that has been initialized as a node.

Because structs are clunkier than basic types, it is common to see them created and passed around with pointers:

...

func main() {
    n1 := &node{100, nil}
    n2 := &node{45, nil}
    n1.next = n2
    fmt.Println(n1.childSum(2))
}

func (n *node) childSum(extra int) int {
    // No dereferencing needed to access fields
    return n.value + n.next.value + extra
}

A final note: structs can be defined at the module level or at the block level, but are generally defined at the module level. If defined in a block, they lose the ability to use methods.

Exercises

Implement a circularly linked integer list.

Tips

  • The container package may be a great reference for the exercise.

Further Reading

Go support composition over inheritance. Here is an example, or for more detail head over to Ardan Labs.

Another interesting post on empty structs.


prev -- up -- next