Documentation
¶
Overview ¶
Package traversal provides generic Iterator and Generator interfaces.
Index ¶
- func AsChannel[T any](it Iterator[T], ctx context.Context) <-chan T
- func Drain[Element any](it Iterator[Element]) ([]Element, error)
- func Pipe[Element any](dst Generator[Element], src Iterator[Element]) (ok bool)
- type Generator
- type Iterator
- func Connect[Element1, Element2 any](source Iterator[Element1], ...) Iterator[Element2]
- func Empty[Element any](err error) Iterator[Element]
- func FromChannel[T any](in <-chan T) (Iterator[T], context.Context)
- func Map[Element1, Element2 any](source Iterator[Element1], f func(Element1) Element2) Iterator[Element2]
- func New[T any](source func(generator Generator[T])) Iterator[T]
- func Sequence[T any](seq RangeFunc[T]) Iterator[T]
- func Slice[T any](elements []T) Iterator[T]
- type RangeFunc
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AsChannel ¶
AsChannel returns a channel that receives each element of the underlying iterator. The channel and underlying iterator are closed once the iterator has no more values, or the context is cancelled. Note that a cancellation of the context might not be registered until the Next method of the iterator has returned.
The caller should ensure that the returned channel is drained, to ensure the iterator is garbage collected.
Example ¶
package main import ( "context" "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { it := traversal.Slice([]int{0, 1, 2, 3, 4, 5}) for i := range traversal.AsChannel(it, context.Background()) { fmt.Print(i, " ") } }
Output: 0 1 2 3 4 5
func Drain ¶
Drain iterates all values in it until no more values are returned. All returned values are stored in a slice which is returned to the caller.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { source := traversal.Slice([]int{0, 1, 2, 3, 4, 5}) fmt.Println(traversal.Drain(source)) }
Output: [0 1 2 3 4 5] <nil>
func Pipe ¶
Pipe pipes elements from src into dst. If any error occurs in src, the same error is sent to dst.
A return value of false indicates that the iterator requested cancellation, ok an error occurred. In such a case, the caller should not continue the use of dst.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { iterator := traversal.New(func(generator traversal.Generator[int]) { source := traversal.Slice([]int{0, 1, 2, 3, 4, 5}) traversal.Pipe(generator, source) }) for iterator.Next() { fmt.Println(iterator.Datum()) } fmt.Println(iterator.Err()) }
Output: 0 1 2 3 4 5 <nil>
Types ¶
type Generator ¶
type Generator[T any] interface { // Yield yields an item to the receiving end. // A return value of false indicates that the receiving end has been closed and the generator should stop producing values early. Yield(datum T) bool // YieldError yields an error to the receiving end. // Calling YieldError(nil) has no effect. // // If the receiving end of this iterator requested cancellation, the return value is false. // Otherwise, if the return value indicates if a non-nil error has been passed. YieldError(err error) bool // Returned indicates if the Return method was called. Returned() bool // Return closes this generator. // // Calling Return multiple times is an error. // Calls to Yield and YieldError after Return are also an error. Return() }
Generator is the opposite of Iterator, allowing values to be sent to a receiving iterator. Methods on a generator may not be called concurrently.
type Iterator ¶
type Iterator[T any] interface { // Next advances this iterator to the next value. // The returned value indicates if there are further values. Next() bool // Datum returns the current value of this iterator. Datum() T // Err returns any error that occurred during iteration. Err() error // Close closes this iterator, indicating to the sender that no more // values would be received. Close() error }
Iterator represents an object that can be iterated over. An iterator is not safe for concurrent access.
A user of an iterator must ensure that the iterator is closed once it is no longer needed. A user should furthermore use the Err() method to check if an error occurred.
A typical use of an iterator would be something like:
var it Iterator[T] // get the iterator from somewhere defer it.Close() for it.Next() { datum := it.Datum() _ = datum // ... do something with datum ... } if err := it.Err(); err != nil { return err // an error occurred! }
func Connect ¶
func Connect[Element1, Element2 any](source Iterator[Element1], f func(element Element1, sender Generator[Element2]) (ok bool)) Iterator[Element2]
Connect creates a new iterator that calls f for every element returned by source. If the pipe function returns false, iteration over the original elements stops.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { source := traversal.Slice([]int{0, 1, 2}) dest := traversal.Connect(source, func(element int, sender traversal.Generator[int]) (ok bool) { sender.Yield(2 * element) sender.Yield(2*element + 1) return true }) for dest.Next() { fmt.Println(dest.Datum()) } fmt.Println(dest.Err()) }
Output: 0 1 2 3 4 5 <nil>
func Empty ¶
Empty returns a new iterator that contains no elements. The Err method will return err, which may be nil.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { thing := traversal.Empty[any](nil) fmt.Println(thing.Next()) fmt.Println(thing.Err()) }
Output: false <nil>
Example (Error) ¶
package main import ( "errors" "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { thing := traversal.Empty[any](errors.New("some error")) fmt.Println(thing.Next()) fmt.Println(thing.Err()) }
Output: false some error
func FromChannel ¶
FromChannel creates a new iterator that receives values from the provided channel. The context is cancelled once the receiving end of the iterator requests cancellation or the input channel is exhausted.
NOTE: Even if the receiving iterator end requests cancellation, the input channel will always be drained. This ensures that any process sending to the iterator can always continue to send values.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { // fill a channel with some numbers // and then close it! in := make(chan int, 6) for i := range cap(in) { in <- i } close(in) // create a channel c, _ := traversal.FromChannel(in) for c.Next() { fmt.Print(c.Datum(), " ") } }
Output: 0 1 2 3 4 5
func Map ¶
func Map[Element1, Element2 any](source Iterator[Element1], f func(Element1) Element2) Iterator[Element2]
Map creates a new iterator that produces the same values as source, but mapped over f. If source produces an error, the returned iterator also produces the same error.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { iterator := traversal.Map( traversal.Slice([]int{1, 2, 3, 4, 5}), func(value int) bool { return value%2 == 0 }, ) for iterator.Next() { fmt.Println(iterator.Datum()) } fmt.Println(iterator.Err()) }
Output: false true false true false <nil>
func New ¶
New creates a new iterator generator pair and returns the iterator.
The generator is passed to the function source. Once source returns, the return method on the generator is called if it has not been already.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { iterator := traversal.New(func(generator traversal.Generator[string]) { if !generator.Yield("hello") { return } if !generator.Yield("world") { return } }) defer iterator.Close() for iterator.Next() { fmt.Println(iterator.Datum()) } fmt.Println(iterator.Err()) }
Output: hello world <nil>
Example (Close) ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { iterator := traversal.New(func(generator traversal.Generator[string]) { if !generator.Yield("hello") { return } if !generator.Yield("world") { return } panic("never reached") }) defer iterator.Close() // request a single item, then close the iterator! for iterator.Next() { fmt.Println(iterator.Datum()) iterator.Close() } fmt.Println(iterator.Err()) }
Output: hello <nil>
Example (Error) ¶
package main import ( "errors" "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { iterator := traversal.New(func(generator traversal.Generator[string]) { if !generator.Yield("hello") { return } generator.YieldError(errors.New("something went wrong")) }) defer iterator.Close() for iterator.Next() { fmt.Println(iterator.Datum()) } fmt.Println(iterator.Err()) }
Output: hello something went wrong
func Sequence ¶
Sequence creates a new iterator from the given RangeFunc.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { seq := traversal.RangeFunc[int](func(yield func(int) bool) { if !yield(42) { return } if !yield(69) { return } }) // turn it into an iterator and drain it! it := traversal.Sequence(seq) fmt.Println(traversal.Drain(it)) }
Output: [42 69] <nil>
func Slice ¶
Slice creates a new Iterator that yields elements from the given slice
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { iterator := traversal.Slice([]int{1, 2, 3, 4, 5}) for iterator.Next() { fmt.Println(iterator.Datum()) } fmt.Println(iterator.Err()) }
Output: 1 2 3 4 5 <nil>
type RangeFunc ¶
RangeFunc 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.
NOTE: This corresponds to the "iter".Seq type from the rangefunc experiment. At some point in the future when rangefunc is stable, and generic aliases are implemented, this will be replaced with an alias to "iter".Seq. See golang issues #61405 and #46477.
func Range ¶
Range turns an iterator into a function compatible with the RangeFunc experiment.
Example ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/traversal" ) func main() { // create a simple iterator it := traversal.New(func(generator traversal.Generator[int]) { if !generator.Yield(42) { return } if !generator.Yield(69) { return } }) rg := traversal.Range(it) rg(func(value int) bool { fmt.Println(value) return true }) }
Output: 42 69