Go Arrays and Slices
array to define an array type; instead, we define the type [n]T as an array of n values of type T.
Arrays
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 Declaration & 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)
}
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 (exclusive).
//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 starts from 0 in Go.
Slice Operations
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 Boundary
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, the following 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:
//file default_boundary.go
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
s = s[1:4]
fmt.Println(s) // [3 5 7]
s = s[:2]
fmt.Println(s) // [3 5]
s = s[1:]
fmt.Println(s) // [5]
}
Slice Length and Capacity
A slice has both a length and a capacity. The length is the number of elements it contains. The capacity is the number of elements in the underlying array, counting from the first element in the slice.
//file slice_cap.go
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
s = s[:0] // Slice to zero length
printSlice(s)
s = s[:4] // Extend length
printSlice(s)
s = s[2:] // Drop first two values
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]
Dynamic Growth
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!")
}
}
Make Function
Slices can be created with the built-in make() function; this is how you create dynamically-sized arrays. It allocates a zeroed array and returns a slice that refers to it.
//file slice_make.go
package main
import "fmt"
func main() {
a := make([]int, 5) // len=5
b := make([]int, 0, 5) // len=0, cap=5
c := b[:2]
d := c[2:5]
fmt.Printf("a len=%d cap=%d %v\n", len(a), cap(a), a)
}
Append Function
Go provides a built-in append function to add new elements to a slice.
func append(s []T, vs ...T) []T
//file slice_append.go
package main
import "fmt"
func main() {
var s []int
s = append(s, 0)
s = append(s, 1)
s = append(s, 2, 3, 4)
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
Range
The range is used to iterate over a slice. The first value is the index, and the second is a copy of the element.
//file range_scan.go
package main
import "fmt"
func main() {
pow := []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}