Arrays and slices
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:
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}
[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:
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}
[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:
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}
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.
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}
copyOf := week copies all seven elements, so changing copyOf[6] doesn't touch week[6], which is still 1. The length is 7: the indexes go from 0 to 6.
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:
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}
[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:
1package main2 3import "fmt"4 5func main() {6 prices := []int{12, 30, 8}7 fmt.Println(prices[2])8 fmt.Println(prices[3])9}
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 2What 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:
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}
[] 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:
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}
[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 _:
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}
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:
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}
[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.
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.
50 107
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}
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].
[72 90 65] [88]
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}
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.
eggs apples
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}
What you learned
- An array like
[3]inthas 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 tolen(s)-1. - An index out of range panics:
index out of range [3] with length 3, thenexit status 2. s = append(s, v)adds to the end; assign the result back.s[a:b]takes a part:ais included,bis not.for i, v := range swalks through a slice; use_for what you don't need.make([]int, 5)builds a slice of 5 zero values.