--- date: 20200828 id: 8b5fb822-d1ad-46de-9299-37e3d3f5108c title: Golang slices --- # Basics A slice is a dynamically sized, flexible view into the elements of an array. Apparently they are much more common than arrays. Initialization is pretty straight forward: ``` 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) } ``` Slices are like references. Change something in the slice and the [array](20200828182327-arrays) it references also changes ``` go package main import "fmt" func main() { names := [4]string{ "John", "Paul", "George", "Ringo", } fmt.Println(names) a := names[0:2] b := names[1:3] fmt.Println(a, b) b[0] = "XXX" fmt.Println(a, b) fmt.Println(names) } ``` Slices can contain any type, including other slices: ``` go package main import ( "fmt" "strings" ) func main() { // Create a tic-tac-toe board. board := [][]string{ []string{"_", "_", "_"}, []string{"_", "_", "_"}, []string{"_", "_", "_"}, } // The players take turns. board[0][0] = "X" board[2][2] = "O" board[1][2] = "X" board[1][0] = "O" board[0][2] = "X" for i := 0; i < len(board); i++ { fmt.Printf("%s\n", strings.Join(board[i], " ")) } } ``` # Slice literals A slice literal is like an array, but without the length, so we add more stuff to it later ``` go package main import "fmt" func main() { q := []int{2, 3, 5, 7, 11, 13} fmt.Println(q) r := []bool{true, false, true, true, false, true} fmt.Println(r) s := []struct { i int b bool }{ {2, true}, {3, false}, {5, true}, {7, true}, {11, false}, {13, true}, } fmt.Println(s) } ``` # Slice defaults You can omit high and low bounds. As one would expect these default to 0 and slice length respectively ``` 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) } ``` # Slice length and capacity One can lookup slice length (length of the slice) and capacity (length of the array the slice references) ``` 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) } ``` # Nil slices Empty slices are equal to `nil`. Maybe that's a good idea, maybe it isn't. Typing this i'm too tired to give rational input to this philosophical quagmire. ``` go package main import "fmt" func main() { var s []int fmt.Println(s, len(s), cap(s)) if s == nil { fmt.Println("nil!") } } ``` # Make Slices can be created with the `make` function, this way you can treat them like arrays that we know and love. ``` 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) } ``` # Append New elements can be added to a slice with the [append](https://golang.org/pkg/builtin/#append) function ``` 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) } ``` # Range You can iterate over slices with `range` ``` 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) } } ``` Index or value can be skipped by using `_`. In case you only want the index, just omit the second variable entirely: ``` 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) } } ```