Patterns: behavior · 3 MIN READ

Iterator: yield values without exposing storage

Use iter.Seq or a small Next API and honor early termination.

Use iter.Seq or a small Next API and honor early termination. Iterator gives callers sequential access without revealing collection internals. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.

Behavioral pattern · A MAP OF THE IDEA

  1. Producer generates a value
  2. Consumer receives it through yield
  3. False return stops production

Useful when

  • Traversal should hide collection representation
  • Values can be produced lazily

Watch out

  • Errors and cleanup need explicit contracts
  • A slice range may already be sufficient

Implementation & operation cost: Low

Fit depends on the task

Small tool or CLI5/5
Domain-rich application4/5
Independent distributed services3/5

Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.

01

The design decision

Iterator gives callers sequential access without revealing collection internals. Modern Go supports range over iterator functions through iter.Seq. A producer must stop when yield returns false; continuing work after the caller breaks wastes resources and can violate the iterator contract.

02

A complete Go example

Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.

go
package main

import (
	"fmt"
	"iter"
)

func CountTo(n int) iter.Seq[int] {
	return func(yield func(int) bool) {
		for i := 1; i <= n; i++ {
			if !yield(i) {
				return
			}
		}
	}
}

func main() {
	for n := range CountTo(5) {
		fmt.Println(n)
		if n == 2 {
			break
		}
	}
}

// Output:
// 1
// 2
Read the code

CountTo hides how values are generated and stops immediately after the caller breaks at two. iter.Seq is available from Go 1.23. The iterator uses no goroutine or channel because synchronous production is enough.

03

Tradeoffs and the simpler alternative

For fallible streams, define how errors are delivered, such as iter.Seq2[Value, error] or an Err method. Resource-owning iterators need cleanup on early termination. Ranging a slice is simpler when the caller already owns a small in-memory collection.

TAKE THIS WITH YOU

Must stop producing when yield returns false. For fallible streams, define how errors are delivered, such as iter.Seq2[Value, error] or an Err method. Resource-owning iterators need cleanup on early termination. Ranging a slice is simpler when the caller already owns a small in-memory collection.

Check your understanding

Which statement best describes Iterator: yield values without exposing storage?

Go to the source

Progress stays in this browser. No account needed.