How do range-over-func iterators work on slices and maps, and what happens if an iterator ignores yield's return value?
Question 75HardGo 1.22 to 1.25
Since Go 1.23 a for range loop can take a function of type func(yield func(K, V) bool) (that is, iter.Seq2[K, V]), func(yield func(V) bool) (iter.Seq[V]) or func(yield func() bool). The compiler turns the loop body into the yield function. yield returns false when the body executes break or return, and the iterator must stop at that point.
for i, v := range slices.Backward([]string{"a", "b", "c"}) {
if i == 0 {
break
}
fmt.Printf("%d%s ", i, v)
}
fmt.Println() // prints: 2c 1b
// A broken iterator: ignores yield's result
func bad(yield func(int) bool) {
for i := range 3 {
yield(i)
}
}
for v := range bad {
if v == 1 {
break
}
}
// panic: runtime error: range function continued iteration after function for loop body returned false
The correct pattern checks every call: if !yield(v) { return }. The runtime checks this contract and panics instead of running the loop body again after a break. That keeps break, return, goto and defer inside the loop body working as they do in ordinary loops.
Other points worth knowing:
- Iterators are usually lazy and single-pass.
maps.Keys(m)reads the live map, so changes to the map during iteration follow the normal map rules. - A
deferinside the loop body runs when the enclosing function returns, not when the iterator returns. - Pull-style use is available through
iter.Pull, which returnsnextandstopfunctions. Always callstop(usually withdefer), or the iterator's goroutine-like state leaks. - Useful Go 1.23 helpers:
slices.All,Values,Backward,Collect,AppendSeq,Sorted,Chunk. Go 1.24 addedstrings.Lines,SplitSeqandFieldsSeq, which split without building a[]string.
More on Arrays, Slices, Maps & Strings
- Q73What does this print? (map of slices built from a shared base)
- Q74What does this print? (range over a nil pointer to an array, and range over an int)
- Q76What is the unique package (Go 1.23), and how does it help with memory for repeated strings?