Go: Range loops (for each loops) explained

Range statements iterate over slices, arrays, strings, maps or channels.

Basics

a := []string{"Foo", "Bar"}
for i, s := range a {
	fmt.Println(i, s)
}
0 Foo
1 Bar
  • The range expression, a, is evaluated once before beginning the loop.
  • The iteration values are assigned to the respective iteration variables, i and s, as in an assignment statement.
  • The second iteration variable is optional.
  • If a slice or map is nil, the number of iterations is 0.

Strings

For a string, the loop iterates over Unicode code points.

for i, ch := range "日本語" {
	fmt.Printf("%#U starts at byte position %d\n", ch, i)
}
U+65E5 '日' starts at byte position 0
U+672C '本' starts at byte position 3
U+8A9E '語' starts at byte position 6
  • The index is the first byte of a UTF-8-encoded code point; the second value, of type rune, is the value of the code point.
  • For an invalid UTF-8 sequence, the second value will be 0xFFFD, and the iteration will advance a single byte.

Maps

The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next.

m := map[string]int{
	"one":   1,
	"two":   2,
	"three": 3,
}
for k, v := range m {
	fmt.Println(k, v)
}
two 2
three 3
one 1
  • If a map entry that has not yet been reached is removed during iteration, this value will not be produced.
  • If a map entry is created during iteration, that entry may or may not be produced.

Channels

For channels, the iteration values are the successive values sent on the channel until closed.

ch := make(chan int)
go func() {
	ch <- 1
	ch <- 2
	ch <- 3
	close(ch)
}()
for n := range ch {
	fmt.Println(n)
}
1
2
3
  • For a nil channel, the range loop blocks forever.

Comments