Iterators and Generators in Go
Learn iteration in Go: for-range over collections and channels, custom iteration patterns, and generator-style sequences using channels.
Iteration in Go
Go has no separate iterator protocol like some languages. Instead, you use `for range` over built-in types: slices, maps, strings, and channels. Ranging over a channel is pull-based: the consumer receives values one at a time, and the producer can run in another goroutine. That gives you lazy, on-demand flow similar to generators.
1. for range over Slice
Iterate elements, index, or both.
2. for range over Channel
Consume values until the channel is closed.
Custom Iteration
When you need custom iteration logic—for example, filtering, stepping, or producing values from a function—you can expose a channel that callers range over, or provide a callback that your function invokes for each item.
1. Function that Returns a Channel
Producer goroutine sends values and closes.
Custom Iterators (Go 1.23+)
Go 1.23 added **range over function types**: you can write `for v := range myFunc` when `myFunc` is an iterator function that accepts a **yield** callback and calls it for each value. The standard library package `iter` defines `Seq[V]` and `Seq2[K,V]` for these iterator types. If `yield` returns `false`, the iterator should stop. Your module must use Go 1.23 or later (`go 1.23` in `go.mod`) to use this feature.
1. Range over an Iterator Function
Function that takes yield and is used with for range.
2. iter with slices and maps
Use slices.Values, maps.Keys, and maps.Values as iterators.
Generator-Style Pattern
In Go, a "generator" is usually a function that starts a goroutine, returns a channel, and sends values on that channel. The consumer pulls values with `for range`. Execution is lazy: values are produced only when the consumer is ready to receive.
1. Basic Generator
Yield a sequence of values from a goroutine.
Lazy and Bounded Sequences
Channel-based producers can generate values on demand without storing the whole sequence in memory. For unbounded or long-running streams, the producer should close the channel when done or respect a cancellation signal (e.g. context) so the consumer can stop.
1. Unbounded ID Generator
Infinite sequence; consumer decides when to stop.
2. Batch (Chunk) Iteration
Process a slice in fixed-size chunks.
Pitfalls and Best Practices
Generator-style code that uses channels and goroutines must close channels when production is finished and avoid leaving producer goroutines blocked forever. Prefer closing the channel from the producer so that consumers can always detect the end of the stream.
1. Close from Producer, Receive in Consumer
Single producer closes; consumer ranges until close.