mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
iter: add doc comment from proposal
Add the doc comment from the proposal, lightly edited. The edits are to drop mention of value-error Seq2 usage and to adjust for the bool result changes. Fixes #61897. Change-Id: Iaffbaa301064b2f8739956d602ca5fa23c89a269 Reviewed-on: https://go-review.googlesource.com/c/go/+/591096 Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
f27a40ce5f
commit
fe36ce669c
194
src/iter/iter.go
194
src/iter/iter.go
@ -2,8 +2,186 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Package iter provides basic definitions and operations
|
/*
|
||||||
// related to iteration in Go.
|
Package iter provides basic definitions and operations related to
|
||||||
|
iterators over sequences.
|
||||||
|
|
||||||
|
# Iterators
|
||||||
|
|
||||||
|
An iterator is a function that passes successive elements of a
|
||||||
|
sequence to a callback function, conventionally named yield.
|
||||||
|
The function stops either when the sequence is finished or
|
||||||
|
when yield returns false, indicating to stop the iteration early.
|
||||||
|
This package defines [Seq] and [Seq2]
|
||||||
|
(pronounced like seek—the first syllable of sequence)
|
||||||
|
as shorthands for iterators that pass 1 or 2 values per sequence element
|
||||||
|
to yield:
|
||||||
|
|
||||||
|
type (
|
||||||
|
Seq[V any] func(yield func(V) bool)
|
||||||
|
Seq2[K, V any] func(yield func(K, V) bool)
|
||||||
|
)
|
||||||
|
|
||||||
|
Seq2 represents a sequence of paired values, conventionally key-value
|
||||||
|
or index-value pairs.
|
||||||
|
|
||||||
|
Yield returns true if the iterator should continue with the next
|
||||||
|
element in the sequence, false if it should stop.
|
||||||
|
|
||||||
|
Iterator functions are most often called by a range loop, as in:
|
||||||
|
|
||||||
|
func PrintAll[V any](seq iter.Seq[V]) {
|
||||||
|
for _, v := range seq {
|
||||||
|
fmt.Println(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Naming Conventions
|
||||||
|
|
||||||
|
Iterator functions and methods are named for the sequence being walked:
|
||||||
|
|
||||||
|
// All returns an iterator over all elements in s.
|
||||||
|
func (s *Set[V]) All() iter.Seq[V]
|
||||||
|
|
||||||
|
The iterator method on a collection type is conventionally named All,
|
||||||
|
because it iterates a sequence of all the values in the collection.
|
||||||
|
|
||||||
|
For a type containing multiple possible sequences, the iterator's name
|
||||||
|
can indicate which sequence is being provided:
|
||||||
|
|
||||||
|
// Cities returns an iterator over the major cities in the country.
|
||||||
|
func (c *Country) Cities() iter.Seq[*City]
|
||||||
|
|
||||||
|
// Languages returns an iterator over the official spoken languages of the country.
|
||||||
|
func (c *Country) Languages() iter.Seq[string]
|
||||||
|
|
||||||
|
If an iterator requires additional configuration, the constructor function
|
||||||
|
can take additional configuration arguments:
|
||||||
|
|
||||||
|
// Scan returns an iterator over key-value pairs with min ≤ key ≤ max.
|
||||||
|
func (m *Map[K, V]) Scan(min, max K) iter.Seq2[K, V]
|
||||||
|
|
||||||
|
// Split returns an iterator over the (possibly-empty) substrings of s
|
||||||
|
// separated by sep.
|
||||||
|
func Split(s, sep string) iter.Seq[string]
|
||||||
|
|
||||||
|
When there are multiple possible iteration orders, the method name may
|
||||||
|
indicate that order:
|
||||||
|
|
||||||
|
// All returns an iterator over the list from head to tail.
|
||||||
|
func (l *List[V]) All() iter.Seq[V]
|
||||||
|
|
||||||
|
// Backward returns an iterator over the list from tail to head.
|
||||||
|
func (l *List[V]) Backward() iter.Seq[V]
|
||||||
|
|
||||||
|
// Preorder returns an iterator over all nodes of the syntax tree
|
||||||
|
// beneath (and including) the specified root, in depth-first preorder,
|
||||||
|
// visiting a parent node before its children.
|
||||||
|
func Preorder(root Node) iter.Seq[Node]
|
||||||
|
|
||||||
|
# Single-Use Iterators
|
||||||
|
|
||||||
|
Most iterators provide the ability to walk an entire sequence:
|
||||||
|
when called, the iterator does any setup necessary to start the
|
||||||
|
sequence, then calls yield on successive elements of the sequence,
|
||||||
|
and then cleans up before returning. Calling the iterator again
|
||||||
|
walks the sequence again.
|
||||||
|
|
||||||
|
Some iterators break that convention, providing the ability to walk a
|
||||||
|
sequence only once. These “single-use iterators” typically report values
|
||||||
|
from a data stream that cannot be rewound to start over.
|
||||||
|
Calling the iterator again after stopping early may continue the
|
||||||
|
stream, but calling it again after the sequence is finished will yield
|
||||||
|
no values at all, immediately returning true. Doc comments for
|
||||||
|
functions or methods that return single-use iterators should document
|
||||||
|
this fact:
|
||||||
|
|
||||||
|
// Lines returns an iterator over lines read from r.
|
||||||
|
// It returns a single-use iterator.
|
||||||
|
func (r *Reader) Lines() iter.Seq[string]
|
||||||
|
|
||||||
|
# Pulling Values
|
||||||
|
|
||||||
|
Functions and methods that accept or return iterators
|
||||||
|
should use the standard [Seq] or [Seq2] types, to ensure
|
||||||
|
compatibility with range loops and other iterator adapters.
|
||||||
|
The standard iterators can be thought of as “push iterators”, which
|
||||||
|
push values to the yield function.
|
||||||
|
|
||||||
|
Sometimes a range loop is not the most natural way to consume values
|
||||||
|
of the sequence. In this case, [Pull] converts a standard push iterator
|
||||||
|
to a “pull iterator”, which can be called to pull one value at a time
|
||||||
|
from the sequence. [Pull] starts an iterator and returns a pair
|
||||||
|
of functions—next and stop—which return the next value from the iterator
|
||||||
|
and stop it, respectively.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
// Pairs returns an iterator over successive pairs of values from seq.
|
||||||
|
func Pairs[V any](seq iter.Seq[V]) iter.Seq2[V, V] {
|
||||||
|
return func(yield func(V, V) bool) bool {
|
||||||
|
next, stop := iter.Pull(seq)
|
||||||
|
defer stop()
|
||||||
|
v1, ok1 := next()
|
||||||
|
v2, ok2 := next()
|
||||||
|
for ok1 || ok2 {
|
||||||
|
if !yield(v1, v2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
If clients do not consume the sequence to completion, they must call stop,
|
||||||
|
which allows the iterator function to finish and return. As shown in
|
||||||
|
the example, the conventional way to ensure this is to use defer.
|
||||||
|
|
||||||
|
# Standard Library Usage
|
||||||
|
|
||||||
|
A few packages in the standard library provide iterator-based APIs,
|
||||||
|
most notably the [maps] and [slices] packages.
|
||||||
|
For example, [maps.Keys] returns an iterator over the keys of a map,
|
||||||
|
while [slices.Sorted] collects the values of an iterator into a slice,
|
||||||
|
sorts them, and returns the slice, so to iterate over the sorted keys of a map:
|
||||||
|
|
||||||
|
for _, key := range slices.Sorted(maps.Keys(m)) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mutation
|
||||||
|
|
||||||
|
Iterators provide only the values of the sequence, not any direct way
|
||||||
|
to modify it. If an iterator wishes to provide a mechanism for modifying
|
||||||
|
a sequence during iteration, the usual approach is to define a position type
|
||||||
|
with the extra operations and then provide an iterator over positions.
|
||||||
|
|
||||||
|
For example, a tree implementation might provide:
|
||||||
|
|
||||||
|
// Positions returns an iterator over positions in the sequence.
|
||||||
|
func (t *Tree[V]) Positions() iter.Seq[*Pos]
|
||||||
|
|
||||||
|
// A Pos represents a position in the sequence.
|
||||||
|
// It is only valid during the yield call it is passed to.
|
||||||
|
type Pos[V any] struct { ... }
|
||||||
|
|
||||||
|
// Pos returns the value at the cursor.
|
||||||
|
func (p *Pos[V]) Value() V
|
||||||
|
|
||||||
|
// Delete deletes the value at this point in the iteration.
|
||||||
|
func (p *Pos[V]) Delete()
|
||||||
|
|
||||||
|
// Set changes the value v at the cursor.
|
||||||
|
func (p *Pos[V]) Set(v V)
|
||||||
|
|
||||||
|
And then a client could delete boring values from the tree using:
|
||||||
|
|
||||||
|
for p := range t.Positions() {
|
||||||
|
if boring(p.Value()) {
|
||||||
|
p.Delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
package iter
|
package iter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -15,11 +193,13 @@ import (
|
|||||||
// Seq is an iterator over sequences of individual values.
|
// Seq is an iterator over sequences of individual values.
|
||||||
// When called as seq(yield), seq calls yield(v) for each value v in the sequence,
|
// When called as seq(yield), seq calls yield(v) for each value v in the sequence,
|
||||||
// stopping early if yield returns false.
|
// stopping early if yield returns false.
|
||||||
|
// See the [iter] package documentation for more details.
|
||||||
type Seq[V any] func(yield func(V) bool)
|
type Seq[V any] func(yield func(V) bool)
|
||||||
|
|
||||||
// Seq2 is an iterator over sequences of pairs of values, most commonly key-value pairs.
|
// Seq2 is an iterator over sequences of pairs of values, most commonly key-value pairs.
|
||||||
// When called as seq(yield), seq calls yield(k, v) for each pair (k, v) in the sequence,
|
// When called as seq(yield), seq calls yield(k, v) for each pair (k, v) in the sequence,
|
||||||
// stopping early if yield returns false.
|
// stopping early if yield returns false.
|
||||||
|
// See the [iter] package documentation for more details.
|
||||||
type Seq2[K, V any] func(yield func(K, V) bool)
|
type Seq2[K, V any] func(yield func(K, V) bool)
|
||||||
|
|
||||||
type coro struct{}
|
type coro struct{}
|
||||||
@ -45,10 +225,13 @@ func coroswitch(*coro)
|
|||||||
// no longer interested in next values and next has not yet
|
// no longer interested in next values and next has not yet
|
||||||
// signaled that the sequence is over (with a false boolean return).
|
// signaled that the sequence is over (with a false boolean return).
|
||||||
// It is valid to call stop multiple times and when next has
|
// It is valid to call stop multiple times and when next has
|
||||||
// already returned false.
|
// already returned false. Typically, callers should “defer stop()”.
|
||||||
//
|
//
|
||||||
// It is an error to call next or stop from multiple goroutines
|
// It is an error to call next or stop from multiple goroutines
|
||||||
// simultaneously.
|
// simultaneously.
|
||||||
|
//
|
||||||
|
// If the iterator panics during a call to next (or stop),
|
||||||
|
// then next (or stop) itself panics with the same value.
|
||||||
func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func()) {
|
func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func()) {
|
||||||
var (
|
var (
|
||||||
v V
|
v V
|
||||||
@ -157,10 +340,13 @@ func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func()) {
|
|||||||
// no longer interested in next values and next has not yet
|
// no longer interested in next values and next has not yet
|
||||||
// signaled that the sequence is over (with a false boolean return).
|
// signaled that the sequence is over (with a false boolean return).
|
||||||
// It is valid to call stop multiple times and when next has
|
// It is valid to call stop multiple times and when next has
|
||||||
// already returned false.
|
// already returned false. Typically, callers should “defer stop()”.
|
||||||
//
|
//
|
||||||
// It is an error to call next or stop from multiple goroutines
|
// It is an error to call next or stop from multiple goroutines
|
||||||
// simultaneously.
|
// simultaneously.
|
||||||
|
//
|
||||||
|
// If the iterator panics during a call to next (or stop),
|
||||||
|
// then next (or stop) itself panics with the same value.
|
||||||
func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func()) {
|
func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func()) {
|
||||||
var (
|
var (
|
||||||
k K
|
k K
|
||||||
|
Loading…
x
Reference in New Issue
Block a user