mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +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
|
||||
// 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
|
||||
|
||||
import (
|
||||
@ -15,11 +193,13 @@ import (
|
||||
// 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,
|
||||
// stopping early if yield returns false.
|
||||
// See the [iter] package documentation for more details.
|
||||
type Seq[V any] func(yield func(V) bool)
|
||||
|
||||
// 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,
|
||||
// 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 coro struct{}
|
||||
@ -45,10 +225,13 @@ func coroswitch(*coro)
|
||||
// no longer interested in next values and next has not yet
|
||||
// signaled that the sequence is over (with a false boolean return).
|
||||
// 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
|
||||
// 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()) {
|
||||
var (
|
||||
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
|
||||
// signaled that the sequence is over (with a false boolean return).
|
||||
// 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
|
||||
// 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()) {
|
||||
var (
|
||||
k K
|
||||
|
Loading…
x
Reference in New Issue
Block a user