11. Range
range iterates over elements in a variety of data structures.
If you’re looping over an array, slice, string, or map (more about this later), or reading from a channel (more about this later), a range clause can manage the loop.
1 package main
2
3 import "fmt"
4
5 func main() {
6 nums := []int{2, 3, 4}
7 sum := 0
8 for key, value := range nums {
9 sum += value
10 fmt.Println("key: ", key, " sum is: ", sum)
11 }
12 fmt.Println("Final sum:", sum)
13 }
The output is:
key: 0 sum is: 2
key: 1 sum is: 5
key: 2 sum is: 9
Final sum: 9
If you only need the first item in the range (the key or index), drop the second:
1 for key := range m {
2 if key.expired() {
3 delete(m, key)
4 }
5 }
If you only need the second item in the range (the value), use the blank identifier, an underscore, to discard the first:
1 package main
2
3 import "fmt"
4
5 func main() {
6 nums := []int{2, 3, 4}
7 sum := 0
8 for _, value := range nums {
9 sum += value
10 }
11 fmt.Println("Final sum:", sum)
12 }
The output is:
Final sum: 9
The blank identifier _ as seen above, can be assigned or declared with any value of any type, with the value discarded harmlessly.
Here is a slighly bigger example:
Program: range_ex.go
1 package main
2
3 import "fmt"
4
5 func main() {
6 nums := []int{2, 3, 4}
7
8 //Here we use range to sum the
9 //numbers in a slice. Arrays work
10 //like this too.
11 sum := 0
12 for _, num := range nums {
13 sum += num
14 }
15 fmt.Println("sum:", sum)
16
17 //range on arrays and slices provides
18 //both the index and value for each entry.
19 //Above we didn't need the index, so we
20 //ignored it with the blank identifier _.
21 //Sometimes we actually want the indexes though.
22 for i, num := range nums {
23 if num == 3 {
24 fmt.Println("index:", i)
25 }
26 }
27 }
The output is:
sum: 9
index: 1
You can also use range on strings directly. Then it will break out the individual Unicode characters and their start position, by parsing the UTF-8.
Program: range_str.go
1 package main
2
3 import "fmt"
4
5 func main() {
6 for pos, char := range "a©b" {
7 fmt.Printf("character '%c' starts at byte position %d\n", char, pos)
8 }
9 }
The output is:
character 'a' starts at byte position 0
character `'©'` starts at byte position 1
character 'b' starts at byte position 3
Observe that ‘b’ starts at position 3, which means '©' took 2 bytes.
In the UTF-8 world characters are sometimes called runes. Mostly, when people talk about characters, they mean 8 bit characters. As UTF-8 characters may be up to 32 bits the word rune is used. In this case the type of char is rune. The Go language defines the word rune as an alias for the type int32.
A for range loop, by contrast, decodes one UTF-8-encoded rune on each iteration. Each time around the loop, the index of the loop is the starting position of the current rune, measured in bytes, and the code point is its value.
11.1 Variadic Functions using range
There is a special form available for the last parameter in a Go function. They are known as Variadic functions and can be called with any number of trailing arguments. By using ... before the type name of the last parameter you can indicate that it takes zero or more of those parameters.
Here’s a function that will take an arbitrary number of ints as arguments:
1 package main
2
3 import "fmt"
4
5 func add(args ...int) int {
6 total := 0
7 for _, v := range args {
8 total += v
9 }
10 return total
11 }
12 func main() {
13 fmt.Println(add(1, 2))
14 fmt.Println(add(4, 5, 6))
15 }
The output is:
3
15