iter holds two function types and two functions. Everything in Go that hands back a sequence, maps.Keys and slices.All included, is shaped by what is on this page.
Examples
An iterator is a function that takes yield and calls it once per element.
// Words returns an iterator over the whitespace-separated words in s.
func Words(s string) iter.Seq[string] {
return func(yield func(string) bool) {
for _, w := range strings.Fields(s) {
if !yield(w) {
return
}
}
}
}
func main() {
for w := range Words("the quick brown fox") {
if w == "brown" {
break
}
fmt.Println(w)
}
}the
quickSeq2 yields two values, so the range loop has two variables.
type Inventory struct {
stock map[string]int
}
// All returns an iterator over every item and its count.
func (inv *Inventory) All() iter.Seq2[string, int] {
return func(yield func(string, int) bool) {
for _, name := range []string{"bolt", "nut", "washer"} {
if !yield(name, inv.stock[name]) {
return
}
}
}
}
func main() {
inv := &Inventory{stock: map[string]int{"bolt": 12, "nut": 30, "washer": 0}}
for name, count := range inv.All() {
fmt.Printf("%-7s %d\n", name, count)
}
}bolt 12
nut 30
washer 0Zipping two sequences needs one of them driven by hand.
// Zip pairs values from two sequences, stopping at the shorter one.
func Zip[A, B any](as iter.Seq[A], bs iter.Seq[B]) iter.Seq2[A, B] {
return func(yield func(A, B) bool) {
nextB, stop := iter.Pull(bs)
defer stop()
for a := range as {
b, ok := nextB()
if !ok {
return
}
if !yield(a, b) {
return
}
}
}
}
func main() {
names := slices.Values([]string{"alice", "bob", "carol"})
scores := slices.Values([]int{91, 84})
for name, score := range Zip(names, scores) {
fmt.Println(name, score)
}
}alice 91
bob 84Types
| Type | Description |
|---|---|
type Seq[V any] func(yield func(V) bool) | A sequence of single values. A range loop over one of these calls it. |
Every iterator you write has the same three layers: a function returning a | |
type Seq2[K, V any] func(yield func(K, V) bool) | A sequence of pairs. Key and value, or index and value. |
| |
Functions
| Function | Description |
|---|---|
Pull[V any](seq Seq[V]) (next func() (V, bool), stop func()) | Turns a sequence into a next() you call yourself. |
A pulled iterator is paused between calls, holding whatever the sequence opened. | |
Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func()) next, stop := iter.Pull2(seq) | The same, for a sequence of pairs. |
| |
The yield contract
Check what yield returns. A false means the loop body ran a break, a return, or a goto, and the iterator has to return there and then.
One more call panics. Once yield has returned false, calling it again takes the program down. This is why the check is written as an early return rather than a flag you test later.
Say so when a sequence runs once. An iterator over a network stream or a scanner cannot be restarted, and the caller has no way to tell from the type. Document it on the function that returns it.