๐ŸŽ“ A1Learner
๐Ÿ”
0 of 34 lessons completed

Go Slices in Depth

A slice is a window over the array that holds its values in memory. That array is called the backing array.

A write through a sub-slice shows in the original

head holds the first two values of nums. Writing head[0] changes the shared array, and the capacity of head reaches the end of that array.

package main

import "fmt"

func main() {
	nums := []int{1, 2, 3, 4}
	head := nums[:2]
	head[0] = 99
	fmt.Println(nums)
	fmt.Println("Len:", len(head), "Cap:", cap(head))
}

An append past capacity breaks the sharing

head starts with length 2 and capacity 4. Appending three values needs room for five, so the append moves head to a new array and nums keeps its values.

package main

import "fmt"

func main() {
	nums := []int{1, 2, 3, 4}
	head := nums[:2]
	head = append(head, 5, 6, 7)
	fmt.Println(nums)
	fmt.Println(head)
}

A three-index slice caps the window

The third index sets the capacity of the new slice. With capacity 2, an append cannot write into the array of nums, so it moves to a new array.

package main

import "fmt"

func main() {
	nums := []int{1, 2, 3, 4}
	head := nums[:2:2]
	fmt.Println("Len:", len(head), "Cap:", cap(head))
	head = append(head, 9)
	fmt.Println(nums)
	fmt.Println(head)
}

Length and capacity grow step by step

Each append adds one value to an empty slice. The printed steps show capacity jumping ahead of length when a bigger array is needed.

package main

import "fmt"

func main() {
	var nums []int
	for _, v := range []int{10, 20, 30, 40} {
		nums = append(nums, v)
		fmt.Printf("Len: %d Cap: %d\n", len(nums), cap(nums))
	}
	fmt.Println(nums)
}

Example

package main

import "fmt"

func main() {
	var queue []int
	for _, v := range []int{10, 20, 30} {
		queue = append(queue, v)
		fmt.Printf("Len: %d Cap: %d\n", len(queue), cap(queue))
	}
	window := queue[:2:2]
	window = append(window, 99)
	fmt.Println(queue)
	fmt.Println(window)
}

Key points

  • The length of a slice counts the values inside the window.
  • The capacity of a slice counts from the window start to the end of the backing array.
  • A sub-slice shares the backing array of the slice it was cut from.
  • An append that fits inside the capacity writes into the shared array.
  • An append past the capacity moves the slice to a new, bigger array.
  • A three-index slice sets its own capacity with a second colon and a max index.
  • Capacity grows in steps, and the steps print from len and cap after each append.

In this example, a loop appends 10, 20 and 30 to an empty queue. The printed lines show the capacity steps 1, 2 and 4. A window then takes the first two values with a capacity of 2. Appending 99 to the window moves the window to a new array. The queue still prints its three values, and the window prints 10, 20 and 99.

Note

Cutting a window never copies values, so a small window can keep a big array in memory.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Go Playground

Exercise

A slice is cut as nums[:2:2]. What is the capacity of the new slice?