Basic

Slices and Arrays

Store ordered collections of values using arrays and slices.

What you will see

0 10 1 20 2 30

About 2 min of reading

Try It

A slice is a flexible view over an array, and append grows it for you. You will create a slice, take pieces of it with slicing syntax, and walk it with range.

1

I start with a two-element slice and append a third. append handles the growth automatically, and I print the slice to see the new length.

package main import "fmt" func main() { nums := []int{1, 2} nums = append(nums, 3) fmt.Println(nums) }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
[1 2 3]
append may allocate a larger backing array and copy the data. Reuse the returned slice, or the growth is lost.
2

I take three different pieces with slicing syntax. Each slice is half-open: the start is included and the stop is not. I print all three pieces in order.

package main import "fmt" func main() { arr := []int{1, 2, 3, 4, 5} sub := arr[1:4] fmt.Println(sub) head := arr[:2] fmt.Println(head) tail := arr[3:] fmt.Println(tail) }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
[2 3 4] [1 2] [4 5]
Slicing shares the same backing array, so changes to one slice can show up in another. Give slices only how long you need them.
3

I walk a slice with range to get the index and value of each element. This is the idiomatic way to read a collection without juggling a counter.

package main import "fmt" func main() { nums := []int{10, 20, 30} for i, n := range nums { fmt.Println(i, n) } }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
0 10 1 20 2 30
range yields a copy of each element for value types, so editing the loop variable does not edit the slice.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

A slice references an underlying array; append may copy into a larger array.
1 Slice points to an underlying array
↓
2 append adds an element at the end
↓
3 If capacity is full, a new array is allocated
↓
4 Data is copied and the slice is updated
Why this works
Append and capacity

append adds elements and may reallocate:

s := make([]int, 3, 5)  // len 3, cap 5
s = append(s, 4)        // len 4
s = append(s, 5)        // len 5
s = append(s, 6)        // grows cap to 10

When a slice exceeds its capacity, Go allocates a larger array and copies the data. Reusing the old slice variable avoids subtle bugs.

When you have a choice

Array vs slice

Go has both, but slices are what you use most:

ArraySlice
Sizefixeddynamic
Type[3]int[]int
Declare[3]int{1,2,3}[]int{1,2,3}

An array's size is part of its type. A slice is a lightweight descriptor over an underlying array.

Examples

Declaring slices

Ordered collections

nums := []int{1, 2, 3}
fruits := []string{"a", "b", "c"}
empty := make([]int, 0)

A slice is a flexible view over an array. make([]int, 5) creates a slice of five zeros. append grows a slice:

nums := []int{1, 2}
nums = append(nums, 3)   // [1, 2, 3]

Why it works: slices track length and capacity; append handles growth automatically.

Slicing syntax

Taking a piece

arr := []int{1, 2, 3, 4, 5}
sub := arr[1:4]   // [2, 3, 4]
head := arr[:2]   // [1, 2]
tail := arr[3:]   // [4, 5]

[start:stop] is half-open, it includes start, excludes stop. Omit either end for the whole side.

Range over slices

Iterating collections

nums := []int{10, 20, 30}
for i, n := range nums {
    fmt.Println(i, n)
}

range over a slice yields the index and value of each element. This is the standard way to walk a collection.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Functions
Previous Lesson
Functions
Next Lesson
Structs and Methods
Structs and Methods →