Sage-Code Laboratory
index<--

Go Arrays

In Go arrays are collection of several elements of the same type. Arrays are user defined data types. Notice we do not use keyword array to define an array type instead we define the type [n]T as an array of n values of type T.
array

Array Elements


Simple declaration:

Next expression declares a variable "numbers" as an array of ten (10) integers.

var numbers [10]int

Note: An array's length is part of its type, so arrays cannot be resized. This seems limiting, but don't worry; Go provides a convenient way of working with arrays.

Array initializers:

//file array_init.go
package main

import "fmt"

func main() {
    // declare an array with two elements
	var a [2]string

	a[0] = "Hello" // first element
	a[1] = "World" // second element

	fmt.Println(a[0], a[1])
	fmt.Println(a)

    // declare array with initializers
	primes := [6]int{2, 3, 5, 7, 11, 13}
	fmt.Println(primes)
}

Range

The range is used to create a form of the loop iteration over a slice or a map. When ranging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index.

//file range_scan.go
package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}

Output:

2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
2**5 = 32
2**6 = 64
2**7 = 128

You can skip the index or value by assigning to "_" If you only want the index, drop the ", value" entirely.

//file range_values.go
package main

import "fmt"

func main() {
	pow := make([]int, 10)
	for i := range pow {
		pow[i] = 1 << uint(i) // == 2**i
	}
	for _, value := range pow {
		fmt.Printf("%d\n", value)
	}
}

Output:

2
4
8
16
32
64
128
256
512

Slices

A slice is a dynamically-sized, flexible view into the elements of an array. In practice, slices are much more common than arrays.

The type []T is a slice with elements of type T.

In the next example we define an array "primes" then we create a slice "s" from element 1 (inclusive) to element 4 (inclusive).

//file array_slice.go
package main

import "fmt"

func main() {
	primes := [6]int{2, 3, 5, 7, 11, 13}

	var s []int = primes[1:4]
	fmt.Println(s) // [3 5 7]
}

Note: Remember the element count start from 0 in Go.

References

A slice does not store any data, it just describes a section of an underlying array.

Changing the elements of a slice modifies the corresponding elements of its underlying array.

Other slices that share the same underlying array will see those changes.

//file array_references.go
package main

import "fmt"

func main() {
	names := [4]string{
		"John",
		"Paul",
		"George",
		"Ringo",
	}
	fmt.Println(names)

	b := names[1:3]
	b[0] = "XXX"
	fmt.Println(b)    
	fmt.Println(names)
}

Default boundery

When slicing, you may omit the high or low bounds to use their defaults instead.

The default is zero for the low bound and the length of the slice for the high bound.

For the array: var a [10]int, next slice expressions are equivalent:

a[0:10]
a[:10]
a[0:]
a[:]

In the next example we use slice defaults to create 3 slices from the same array:

//fille default_boundery.go
package main

import "fmt"

func main() {
	s := []int{2, 3, 5, 7, 11, 13}

	s = s[1:4]
	fmt.Println(s)

	s = s[:2]
	fmt.Println(s)

	s = s[1:]
	fmt.Println(s)
}

Output:

[3 5 7]
[3 5]
[5]

Slice length and capacity

A slice has both a length and a capacity. The length of a slice is the number of elements it contains.

The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice.

The length and capacity of a slice s can be obtained using the expressions len(s) and cap(s).

You can extend a slice's length by re-slicing it, provided it has sufficient capacity.

//file slice_cap.go
package main

import "fmt"

func main() {
	s := []int{2, 3, 5, 7, 11, 13}
	printSlice(s)

	// Slice the slice to give it zero length.
	s = s[:0]
	printSlice(s)

	// Extend its length.
	s = s[:4]
	printSlice(s)

	// Drop its first two values.
	s = s[2:]
	printSlice(s)
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]

Nil slices

The zero value of a slice is nil. A nil slice has a length and capacity of 0 and has no underlying array.

//file nil_slice.go
package main

import "fmt"

func main() {
	var s []int
	fmt.Println(s, len(s), cap(s))
	if s == nil {
		fmt.Println("nil!")
	}
}

Output:

[] 0 0
nil!

Make

Slices can be created with the built-in make() function; this is how you create dynamically-sized arrays.

The make() function allocates a zeroed array and returns a slice that refers to that array:

a := make([]int, 5)  // len(a)=5

To specify a capacity, pass a third argument to make:

b := make([]int, 0, 5) // len(b)=0, cap(b)=5

b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:]      // len(b)=4, cap(b)=4

Example:

//file slice_make.go
package main

import "fmt"

func main() {
	a := make([]int, 5)
	printSlice("a", a)

	b := make([]int, 0, 5)
	printSlice("b", b)

	c := b[:2]
	printSlice("c", c)

	d := c[2:5]
	printSlice("d", d)
}

func printSlice(s string, x []int) {
	fmt.Printf("%s len=%d cap=%d %v\n",
		s, len(x), cap(x), x)
}

Output:

a len=5 cap=5 [0 0 0 0 0]
b len=0 cap=5 []
c len=2 cap=5 [0 0]
d len=3 cap=3 [0 0 0]

Append

It is common to append new elements to a slice. Go provides a built-inappend function.

func append(s []T, vs ...T) []T

Examples:

//file slice_append.go
package main

import "fmt"

func main() {
	var s []int
	printSlice(s)

	// append works on nil slices.
	s = append(s, 0)
	printSlice(s)

	// The slice grows as needed.
	s = append(s, 1)
	printSlice(s)

	// We can add more than one element at a time.
	s = append(s, 2, 3, 4)
	printSlice(s)
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

Notes:

Output:

len=0 cap=0 []
len=1 cap=2 [0]
len=2 cap=2 [0 1]
len=5 cap=8 [0 1 2 3 4]

Read next: Maps