Iterators in Go: Range Over Functions
Since Go 1.23, for range can loop over functions. This gives Go a standard way to write iterators for custom data structures, database rows or paginated APIs.
The iterator types
// package iter
type Seq[V any] func(yield func(V) bool)
type Seq2[K, V any] func(yield func(K, V) bool)
An iterator calls yield for each value. If yield returns false (the loop hit break), the iterator must stop.
Writing one
import "iter"
// Evens yields even numbers up to max
func Evens(max int) iter.Seq[int] {
return func(yield func(int) bool) {
for n := 0; n <= max; n += 2 {
if !yield(n) {
return
}
}
}
}
for n := range Evens(10) {
fmt.Println(n) // 0 2 4 6 8 10
}
A paginated API as one stream
func AllOrders(ctx context.Context, c *Client) iter.Seq2[Order, error] {
return func(yield func(Order, error) bool) {
cursor := ""
for {
page, err := c.ListOrders(ctx, cursor)
if err != nil {
yield(Order{}, err)
return
}
for _, o := range page.Orders {
if !yield(o, nil) {
return
}
}
if page.NextCursor == "" {
return
}
cursor = page.NextCursor
}
}
}
for order, err := range AllOrders(ctx, client) {
if err != nil {
return err
}
process(order)
}
Standard library support
keys := slices.Sorted(maps.Keys(ages)) // maps.Keys returns an iterator
evens := slices.Collect(Evens(20)) // iterator -> slice
for i, v := range slices.All(names) { ... } // index and value
for v := range slices.Values(names) { ... }
Also new in Go 1.22: for i := range 10 loops over integers 0 to 9.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.