Kodewick
Start learning →
Lesson 6 of 24Contents

Arrays and slices

Lesson 6 of 24 · Part 2 · Data · about 15 minutes

A variable holds one value. A shopping list, the scores of a class, a week of temperatures: each is a list of values. Go keeps a list of values in a slice:

prog.go
1package main2 3import "fmt"4 5func main() {6	list := []string{"milk", "bread", "eggs"}7	fmt.Println(list)8	fmt.Println("Items:", len(list))9	fmt.Println("First item:", list[0])10}
Output
[milk bread eggs]
Items: 3
First item: milk

[]string means "a list of strings", and the curly braces hold the elements it starts with. len(list) is the number of elements, and list[0] is the first one: indexes start at 0. When fmt.Println shows a slice, it puts the elements in square brackets with spaces between them.

Before slices, a look at what they are built on: arrays.

Arrays have a fixed length

An array's length goes in the square brackets, and it never changes. Elements you haven't set are zero values:

prog.go
1package main2 3import "fmt"4 5func main() {6	var temps [3]int7	fmt.Println(temps)8	temps[0] = 189	temps[2] = 2510	fmt.Println(temps, len(temps))11 12	scores := [4]int{90, 75, 88, 62}13	fmt.Println(scores[1])14}
Output
[0 0 0]
[18 0 25] 3
75

The length is part of the type: [3]int and [4]int are two different types, and you can't assign one to the other.

When you assign an array, Go copies the whole thing. Change the copy and the original stays the same:

prog.go
1package main2 3import "fmt"4 5func main() {6	a := [3]int{1, 2, 3}7	b := a8	b[0] = 1009	fmt.Println("a:", a)10	fmt.Println("b:", b)11}
Output
a: [1 2 3]
b: [100 2 3]

Press Step and watch b := a: a second row of boxes appears in the variables panel, one for a and one for b.

Guess first

What does this show?

1package main2 3import "fmt"4 5func main() {6	week := [7]int{}7	week[6] = 18	copyOf := week9	copyOf[6] = 210	fmt.Println(week[6], copyOf[6], len(copyOf))11}

Arrays aren't used much, because their length can't change. Most of the time you use slices.

Slices can grow

A slice type is []int or []string, with no length in the square brackets. You read and change elements by index, just like an array:

prog.go
1package main2 3import "fmt"4 5func main() {6	prices := []int{12, 30, 8}7	prices[1] = 288	fmt.Println(prices)9	fmt.Println("Last:", prices[len(prices)-1])10}
Output
[12 28 8]
Last: 8

The last element's index is len(prices)-1, because indexes start at 0.

Index out of range

Use an index outside the slice and the program stops. This is called a panic:

prog.go
1package main2 3import "fmt"4 5func main() {6	prices := []int{12, 30, 8}7	fmt.Println(prices[2])8	fmt.Println(prices[3])9}
Output
8
panic: runtime error: index out of range [3] with length 3

goroutine 1 [running]:
main.main(...)
	/tmp/sandbox/prog.go:8 +0x1d
exit status 2

What happened: The index is past the end: valid indexes go from 0 to len - 1.

index out of range [3] with length 3: you asked for element 3, but there are only 3 elements (0, 1 and 2). Below it, goroutine 1 [running]: shows where it happened: in main.main(...), line 8 of prog.go. The last line, exit status 2, says the program stopped with an error. Go never quietly hands you some random value; it stops right away and tells you.

append adds to the end

append adds elements to the end of a slice and returns the longer slice. Assign the result back to the variable:

prog.go
1package main2 3import "fmt"4 5func main() {6	var list []string7	fmt.Println(list, len(list))8	list = append(list, "milk")9	list = append(list, "bread", "eggs")10	fmt.Println(list, len(list))11}
Output
[] 0
[milk bread eggs] 3

var list []string is an empty slice (its zero value is nil, with length 0), and append works on it just fine. You can add several elements at once. Press Step and watch the boxes of list grow.

Slicing a slice

s[1:3] takes the part from index 1 to 3: 1 is included, 3 is not. Leave out the first number to start at the beginning, or the second to go to the end:

prog.go
1package main2 3import "fmt"4 5func main() {6	days := []string{"Mon", "Tue", "Wed", "Thu", "Fri"}7	fmt.Println(days[1:3])8	fmt.Println(days[:2])9	fmt.Println(days[3:])10	fmt.Println(len(days[1:4]))11}
Output
[Tue Wed]
[Mon Tue]
[Thu Fri]
3

s[a:b] has b-a elements. The part you cut out shares its storage with the original slice; lesson 7 explains what that means.

Walking through with range

for i, v := range s goes through a slice one element at a time: i is the index and v is the element. If you don't need the index, write _:

prog.go
1package main2 3import "fmt"4 5func main() {6	scores := []int{90, 75, 88, 62}7	for i, v := range scores {8		fmt.Println(i, v)9	}10 11	total := 012	for _, v := range scores {13		total += v14	}15	fmt.Println("Total:", total)16}
Output
0 90
1 75
2 88
3 62
Total: 315

make builds it first

When you know how many elements you need, make([]int, 5) builds a slice of length 5, all zero values, and you fill it in by index:

prog.go
1package main2 3import "fmt"4 5func main() {6	squares := make([]int, 5)7	fmt.Println(squares)8	for i := range squares {9		squares[i] = i * i10	}11	fmt.Println(squares)12}
Output
[0 0 0 0 0]
[0 1 4 9 16]

With just one variable, for i := range squares gives you only the index. The slice from make already has 5 elements, so you fill them by index, not with append (which would add after those 5).

Practice

Write the code, then press Check. A hint costs nothing; the answer is there when you need it.

Exercise 1

Total of a shopping cart

Finish total so it adds up the prices in the slice and returns the sum. main uses it for two carts and should show 50 and 107.

It should print
50
107
exercise1.go
1package main2 3import "fmt"4 5func total(prices []int) int {6	return 07}8 9func main() {10	fmt.Println(total([]int{12, 30, 8}))11	fmt.Println(total([]int{99, 5, 2, 1}))12}
Output
Press Run or Ctrl+Enter
Exercise 2

Keep the passing scores

Finish passing so it returns a new slice with only the scores of 60 or more, in the same order. It should show [72 90 65] and [88].

It should print
[72 90 65]
[88]
exercise2.go
1package main2 3import "fmt"4 5func passing(scores []int) []int {6	var result []int7	return result8}9 10func main() {11	fmt.Println(passing([]int{72, 45, 90, 65, 59}))12	fmt.Println(passing([]int{30, 88, 12}))13}
Output
Press Run or Ctrl+Enter
Exercise 3

Fix it: the last item

last should return the last element of the slice, but the program panics as soon as it runs. Fix it so it shows eggs and apples.

It should print
eggs
apples
exercise3.go
1package main2 3import "fmt"4 5func last(items []string) string {6	return items[len(items)]7}8 9func main() {10	fmt.Println(last([]string{"milk", "bread", "eggs"}))11	fmt.Println(last([]string{"apples"}))12}
Output
Press Run or Ctrl+Enter

What you learned

  • An array like [3]int has a fixed length that is part of its type; assigning it copies the whole array.
  • A slice like []int{…} can grow; len(s) is its number of elements, and indexes go from 0 to len(s)-1.
  • An index out of range panics: index out of range [3] with length 3, then exit status 2.
  • s = append(s, v) adds to the end; assign the result back.
  • s[a:b] takes a part: a is included, b is not.
  • for i, v := range s walks through a slice; use _ for what you don't need.
  • make([]int, 5) builds a slice of 5 zero values.
Finished this lesson?Mark it. Progress is saved in this browser, and you can undo it.