DMarlon Studio

Lesson 18 · 18 of 20

Looping with range · Go

Loop over slices, maps and strings in Go with for and range: index and value, keys sorted with sort.Strings, and runes for characters.

Go · Looping with range in DMarlon Studio: the example's code and its output in the terminal

range walks through a collection and gives two values on each turn. With a slice they are the index and the value: for i, t := range temps prints each day (i+1, because the index starts at 0) and adds up its temperature. t is a copy: changing it does not change the slice.

With a map, range gives the key and the value, but in a random order that may change from one run to the next. With a single variable, for country := range capitals, you get just the key. The keys are collected, sorted with sort.Strings and then walked with for _, country := range countries; the _ throws away the index.

A Go string is a sequence of bytes in UTF-8, and an accented letter such as á takes two of them. range over a string does not give bytes but runes (rune, a Unicode character), together with the byte position where each one starts: that is why 1:á is followed by 3:l.

So len(city) gives 7 bytes, while len([]rune(city)), which turns the string into a slice of runes, gives the 6 characters of Málaga. %c prints a rune as a character.

Code · main.go

package mainimport (	"fmt"	"sort")func main() {	// Over a slice: the index and a copy of each value.	temps, sum := []float64{18.5, 21, 19.5, 23}, 0.0	for i, t := range temps {		fmt.Printf("Day %d: %.1f\n", i+1, t)		sum += t	}	fmt.Printf("Average: %.2f\n", sum/float64(len(temps)))	// Over a map: key and value, in random order, so sort the keys.	capitals := map[string]string{"Spain": "Madrid", "Italy": "Rome", "France": "Paris"}	countries := make([]string, 0, len(capitals))	for country := range capitals {		countries = append(countries, country)	}	sort.Strings(countries)	for _, country := range countries {		fmt.Println(country, "->", capitals[country])	}	// Over a string: the byte position and each rune (character).	city := "Málaga"	for pos, r := range city {		fmt.Printf("%d:%c ", pos, r)	}	fmt.Println("| bytes:", len(city), "runes:", len([]rune(city)))}

Output · go run main.go

Day 1: 18.5
Day 2: 21.0
Day 3: 19.5
Day 4: 23.0
Average: 20.50
France -> Paris
Italy -> Rome
Spain -> Madrid
0:M 1:á 3:l 4:a 5:g 6:a | bytes: 7 runes: 6

Key points

  • for i, v := range slice gives index and value.
  • for k, v := range m gives key and value, in random order.
  • _ drops the index or the key when you do not need it.
  • range over a string gives runes, not bytes.
  • len(s) counts bytes; len([]rune(s)) counts characters.

Exercise

Use range over the string "Cádiz y León" and count its vowels, with or without an accent, using a switch on each rune.