Arrays in Go

By Aaron O. Ellis

If you’re looking to learn more about arrays in Go, the best place to start is Go Slices: usage and internals on the Go blog. The following merely expands on the article’s points and demonstrates a few gotchas.

For instance, there are multiple ways to initialize both arrays and slices, and it’s not always obvious which one will be created:

Initialization Type
[3]int{1, 2, 3} array
[...]int{1, 2, 3} array
var a [3]int array
a[:] slice
var s []int slice
[]int{1, 2, 3} slice
make([]int, 3) slice

The zero value of a slice may be nil, but don’t expect it to have a length:

log.Println(len(nil))
./nil.go:6: use of untyped nil

Unless you specify a type:

var slice []int = nil
log.Println(len(slice))
// 0

You can use nil as a valid parameter or field value:

type Package struct {
    Name         string
    Dependencies []string
}

func main() {
    unsafe := Package{Name: "unsafe", Dependencies: nil}
    log.Println(unsafe, len(unsafe.Dependencies))
    // {unsafe []} 0 
}

Despite a newly created slice being nil, it is able to undergo append operations immediately. No call to make is necessary:

var Primes []int
Primes = append(Primes, 2, 3, 5, 7)

This also works if the slice is the field of a struct:

type Node struct {
    Name     string
    Children []Node
}

func Nodes() {
    A := Node{Name: "A"}
    B := Node{Name: "B"}
    A.Children = append(A.Children, B)
}

Or a named return value:

func CreateFibonacci() (Fibonacci []int) {
    Fibonacci = append(Fibonacci, 1, 1, 2, 3, 5, 8)
    return
}

Or my favorite, the value of a map:

regions := make(map[string][]string)
regions["Europe"] = append(regions["Europe"], "France", "Germany")
regions["Africa"] = append(regions["Africa"], "Djibouti", "Egypt")

But watch out, the JSON output of a slice will vary depending on the initialization method:

var a []int
jsonA, _ := json.Marshal(a)

b := make([]int, 0)
jsonB, _ := json.Marshal(b)

log.Printf("jsonA: %s\n", jsonA)
log.Printf("jsonB: %s\n", jsonB)
// jsonA: null
// jsonB: []

Golint will suggest replacing the latter syntax despite the difference in output:

slices.go:12:2: can probably use "var b []int" instead

Slices are unhashable and cannot be used as keys:

xy := make(map[[]int]string)
./xy.go:6: invalid map key type []int

But arrays are hashable:

xy := make(map[[2]int]string)
xy[[2]int{3, 4}] = "Battleship"
log.Println(xy)
// map[[3 4]:Battleship]

They are not, however, valid keys in JSON objects:

output, err := json.Marshal(xy)
if err != nil {
    log.Fatal(err)
}
json: unsupported type: map[[2]int]string

Happy Hacking!