iter

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 8, 2024 License: MIT Imports: 6 Imported by: 0

README

iter

A generic lazy iterator framework package that respects errors as values with reverse message passing for resource management.

https://github.com/barbell-math/util/blob/9948c0045f7246acb5c2827ea4b34cb4919fcae9/src/iter/example_test.go#L28-L39

//Example Output:
//Area is 1000.000000 Using step size: 0.000100
//Err is: <nil>

Design

This package takes advantage of the fact that functions can have methods in go. This allows an iterator to be defined as a simple function, as shown below.

https://github.com/barbell-math/util/blob/9948c0045f7246acb5c2827ea4b34cb4919fcae9/src/iter/Common.go#L14-L22 The iter type defined in this package.

Given this iterator type, it can have methods attached to it that can call on their relative 'object' (which would be a function in this case) to get values as needed. Each method then returns a new iterator, allowing the method calls to be chained together. The end result of this is a recursive, lazily evaluated iterator sequence.

There are three parts to any iterator chain, with the middle part being optional:

  1. Producer: The producer is responsible for creating a sequence of values to pass to the rest of the iterators. The source can be a slice, channel, or a single value.
  2. Intermediary: An Intermediary is responsible for taking it's parent iterators values, mutating and/or filtering them, and passing them down to it's child iterator.
  3. Consumer: The consumer is what collects all of the final values and either saves them or performs some other aggregate function with them.
Producers

Producers can be any function that returns an iterator. They are responsible for producing the sequence of values that the rest of the iterator chain consumes. There are several rules that a consumer must obey:

  1. Errors are returned from the producer.
  2. When an error is returned the value of the iterator element that is returned does not have to be valid.
  3. When an error is returned the continue flag must be set to false.
  4. A producer will only perform resource management when it receives the break action, not when it returns the initial error.
Intermediaries

Intermediaries sit between producers and consumers. They consume the values from a parent iterator and (potentially) pass that value to the consumer after (potentially) applying some transformation to the value. There are several rules that an intermediary must obey:

  1. Errors are propagated down to the consumer.
  2. When an error is returned the continue flag must be set to false.
  3. All break actions will be passed up to the producer. This allows resources to be destroyed in a top down fashion.
  4. If an intermediary produces a continue flag that tells the next iterator to stop, it should not clean up its parents or itself, but should simply return the flag to not continue. The consumer will start the destruction process once it sees the command to not continue.

Tip: Next is a very ubiquitous intermediary, most other intermediaries can be expressed using Next making them pseudo-intermediaries. By using this pattern all pseudo-intermediaries are abstracted away from the complex looping logic outlined above and do not need to worry about iterator feedback and message passing.

Consumers

Consumers are the final stage in a iterator sequence. Without a consumer a iterator chain will not be consumed due to the iterator chain being lazily evaluated. There are several rules that a consumer must obey:

  1. When an error is generated no further values should be consumed and the break action should be passed to the consumers parent iterator.
  2. When all elements have been consumed iteration should stop and the break action should be passed to the consumers parent iterator.
  3. All errors generated from a consumers parent iterator chain should be returned to the calling code.

Tip: ForEach is a very ubiquitous consumer. Most other consumers can be represented using ForEach, making them pseudo-consumers. By using this pattern all pseudo-consumers are abstracted away from the complex looping logic outlined above and do not need to worry about iterator feedback and message passing.

Reverse Message Passing

Each iterator chooses one of three actions to attach to the current value in the iterator sequence. These values are managed for each individual iterator, and are passed between the child and parent iterators.

  1. Continue: Signaling to 'accept' the current value and pass it along to the child iterator.
  2. Break: Signaling to ignore the current value and return the signal to stop iterating.
  3. Iterate: Signaling the current iterator to continue iterating and pull the next value in the iterator sequence.

Any iterator can produce an error or signal its child iterator to stop iterating. When this happens, the command to stop iterating must be passed all the way down to the consumer with no action being taken by any of the intermediaries. Recognizing that iteration should stop, the consumer must then call its parent iterator with the Break action. This action must be propagated all the way up to the producer without any intermediaries performing any action. Upon receiving this value the producer should perform it's resource management. Once done, the producer should return any errors and it's child iterator should then perform resource management. Each successive intermediary will then perform it's resource management once it's parent iterator is done until the consumer is reached. This allows for resources to be properly destroyed in a top-down fashion. This pattern of events is demonstrated in the image below.

Reverse Message Passing

Sudo Iterators

The intermediaries and consumers can be further sub-categorized:

  1. Pseudo: Any iterator that is expressed using another iterator. For intermediaries a it is common to use Next and for consumers it is common to use ForEach.

https://github.com/barbell-math/util/blob/9948c0045f7246acb5c2827ea4b34cb4919fcae9/src/iter/PseudoConsumer.go#L65-L77 Example pseudo-consumer

https://github.com/barbell-math/util/blob/9948c0045f7246acb5c2827ea4b34cb4919fcae9/src/iter/PseudoIntermediary.go#L21-L36 Example pseudo-intermediary

  1. Non-Pseudo: Any iterator that is not expressed using another iterator. For examples refer to the ForEach and Next functions.

Tip: If you are looking to extend this package and add more iterators, it is recommended that any new intermediary or consumer iterators are created using the non-pseudo iterators. This will reduce errors and time spent needlessly banging your head against a wall.

Benchmarking

Obviously, there will be overhead when using this package instead of using plain for loops. The example_test.go file not only showcases the example at the top of this readme, but contains benchmarks for three different scenarios. These scenarios are shown below for convenience.

Scenario 1: An over the top implementation using iterators

https://github.com/barbell-math/util/blob/9948c0045f7246acb5c2827ea4b34cb4919fcae9/src/iter/example_test.go#L28-L38

Scenario 2: Another implementation using iterators

https://github.com/barbell-math/util/blob/9948c0045f7246acb5c2827ea4b34cb4919fcae9/src/iter/example_test.go#L53-L59

Scenario 3: A basic for loop

https://github.com/barbell-math/util/blob/9948c0045f7246acb5c2827ea4b34cb4919fcae9/src/iter/example_test.go#L74-77

The benchmarks (gathered from the go benchmark utility) for the scenarios with various step sizes are shown below. Make of these results as you will.

Scenario Step Size Time
1 1 7815 ns/op
2 1 5930 ns/op
3 1 3706 ns/op
1 0.1 84634 ns/op
2 0.1 59650 ns/op
3 0.1 34406 ns/op
1 0.01 765754 ns/op
2 0.01 576928 ns/op
3 0.01 352233 ns/op
1 0.001 7526192 ns/op
2 0.001 5810898 ns/op
3 0.001 3460169 ns/op
1 0.0001 73463321 ns/op
2 0.0001 57991047 ns/op
3 0.0001 34179406 ns/op

Documentation

Overview

This package defines an iterator framework comprized of lazily evaluated, pull style iterators.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FilterToIndex

func FilterToIndex[T any](num int) func(index int, val T) bool

A helper function that can be passed to the [Filter] function that filters elements before a specified index value. Internally, this is how [Skip] is implemented.

func NoOp

func NoOp[T any, U any](val T, res U, err error)

A helper function that can be passed to Parallel as a result operation that performs no action. Helpfull when you want to start a bunch of parallel jobs and do nothing with there results.

func Parallel

func Parallel[T any, U any](
	i Iter[T],
	workerOp func(val T) (U, error),
	resOp func(val T, res U, err error),
	numThreads int,
) error

This function is a consumer.

ForEachParallel will consumer it's parent iterators values and start a new go routine to process the result using the worker operation. As each worker finishes the result operation will be called on the workers results. The result operation is syncronized, so this could be where you collect the results from the parallel workers. The number of go routines that are spawned will be limited to numThreads, which must be >=1.

Types

type Iter

type Iter[T any] func(f IteratorFeedback) (T, error, bool)

Iter is the base type that the entire package is built from. This type defines the function that has methods defined on it such that they can be chained together to form iterator chains. The returned values are as follows:

  • T: the value that will be produced in the iterator sequence
  • error: any error that was generated when attempting to get the next value

in the iterator sequence

  • bool: a flag to indicate whether or not to continue iteration

func ChanElems

func ChanElems[T any](c <-chan T) Iter[T]

This function is a producer.

ChanElems returns an iterator that iterates over the elements in an unbuffered channel. Calling this function will block until the channel receives a value. This producer will never return an error. This funciton does not close the channel once it is done iterating. The channel may still have values present in it once iteration is complete depending on if any other functions in the iterator chain stop iteration early.

func FileLines

func FileLines(path string) Iter[string]

This function is a producer.

FileLines returns an iterator that iterates over the lines in a file. If an error occurs opening the file then no lines will be iterated over and the error will be returned upon the first iteration of the producer.

func Join

func Join[T any, U any](
	i1 Iter[T],
	i2 Iter[U],
	factory func() basic.Variant[T, U],
	decider func(left T, right U) bool,
) Iter[basic.Variant[T, U]]

This function is a producer.

Join takes two iterators and a decider function and returns an iterator that consumes both supplied iterators, returning a single value at a time based on the return value from the decider function. The number of values returned will equal the total number of values returned from both of the supplied iterators. Errors from the supplied iterators will be returned by this iterator.

func JoinSame

func JoinSame[T any](
	i1 Iter[T],
	i2 Iter[T],
	factory func() basic.Variant[T, T],
	decider func(left T, right T) bool,
) Iter[T]

This function is a producer.

JoinSame takes two iterators and a decider function and returns an iterator that consumes both supplied iterators, returning a single value at a time based on the return value from the decider function. The number of values returned will equal the total number of values returned from both of the supplied iterators. Errors from the supplied iterators will be returned by this iterator.

func Map

func Map[T any, U any](
	i Iter[T],
	op func(index int, val T) (U, error),
) Iter[U]

This function is an intermediary.

Map will create a mapping between value of one iterator and values of another iterator. Iteration will stop if an error is generated.

func MapElems

func MapElems[K comparable, V any](
	m map[K]V,
	factory func() basic.Pair[K, V],
) Iter[basic.Pair[K, V]]

This function is a producer.

MapElems returns an iterator that iterates over a maps key,value pairs. Do not confuse this with the Map intermediary function. This producer will never return an error. This producer is not thread safe. If the underlying map value it changed while being iterated over behavior is undefined.

func MapKeys

func MapKeys[K comparable, V any](m map[K]V) Iter[K]

This function is a producer.

MapElems returns an iterator that iterates over a maps key values. Do not confuse this with the Map intermediary function. This producer will never return an error. This producer is not thread safe. If the underlying map value it changed while being iterated over behavior is undefined.

func MapVals

func MapVals[K comparable, V any](m map[K]V) Iter[V]

This function is a producer.

MapElems returns an iterator that iterates over a maps values. Do not confuse this with the Map intermediary function. This producer will never return an error. This producer is not thread safe. If the underlying map value it changed while being iterated over behavior is undefined.

func Next

func Next[T any, U any](i Iter[T],
	op func(index int, val T, status IteratorFeedback) (IteratorFeedback, U, error),
) Iter[U]

This function is an intermediary.

Next will take it's parent iterator and consume its values. As it does this it will apply the operation (op) function to the value before passing on the transformed value to it's child iterator. If an error is generated iteration will stop.

func NoElem

func NoElem[T any]() Iter[T]

This function is a producer.

NoElem provides an iterator that returns no elements. NoElem returns an empty iterator.

func PntrToVal

func PntrToVal[T any](i Iter[*T]) Iter[T]

This function is an intermediary.

PntrToVal will map a stream of pointers to values to a stream of values. PntrToVal will stop iteration if an error is returned from it's parent iterator regardless of if it has fully consumed it's input stream of values. PntrToVal will never be the cause of an error.

func Range

func Range[
	T ~int | ~int8 | ~int16 | ~int32 | ~int64,
](start T, stop T, jump T) Iter[T]

This funciton is a producer.

Range returns an iterator that produces a sequence of values according to the values that are given as parameters. The sequence of values that will be returned starts with the start value, and increments by the amount specified by the jump parameter. It will stop once it reaches the stop value, exclusively, meaning the last value will not be included. There are no conditions to check for infinite loops. A jump of 0 will always result in a infinite loop as long as start!=stop. No errors will ever be returned by this producer.

func Recurse

func Recurse[T any](
	root Iter[T],
	shouldRecurse func(v T) bool,
	iterValToIter func(v T) Iter[T],
) Iter[T]

This function is a producer.

Recurse will return an iterator that recursively returns values from the supplied iterator. This iterator will enforce root-left-right traversal. This order is the only available order because once an iterator has produced a value there is no way to "push" it back.

Recurse takes a root iterator where the recursion begins. This iterator can return as many values as it needs, there is no limitation holding to only produce one value.

The shouldRecurse function should return true if the current value needs to be recursed upon.

The iterValToIter takes a value from an iterator and returns an iterator over that value. This is where the recursion happens.

func SequentialElems

func SequentialElems[T any](_len int, get func(i int) (T, error)) Iter[T]

This function is a producer.

SequentialElems returns an iterator that iterates over a general container using the get function in combination with the length argument. Note that unlike the SliceElems and StrElems producers this producer can return an error.

func SliceElemPntrs

func SliceElemPntrs[T any](s []T) Iter[*T]

This function is a producer.

SliceElemPntrs returns an iterator that iterates over the supplied slices elements, providing points to the elements in the slice rather than the elements themselves. No error will ever be returned by this producer. This producer is not thread safe. If the underlying slice is modified while it is being iterated over the behavior will be undefined. For a thread safe implementation of SliceElemPntrs use the SyncedVector.Elems method from the collections package.

func SliceElems

func SliceElems[T any](s []T) Iter[T]

This function is a producer.

SliceElems returns an iterator that iterates over the supplied slices elements. No error will ever be returned by this producer. This producer is not thread safe. If the underlying slice is modified while it is being iterated over the behavior will be undefined. For a thread safe implementation of SliceElems use the SyncedVector.Elems method from the collections package.

func StrElems

func StrElems(s string) Iter[byte]

This function is a producer.

StrElems returns an iterator that iterates over the supplied strings characters. No error will ever be returned by this producer.

func ValElem

func ValElem[T any](val T, err error, repeat int) Iter[T]

This function is a producer.

ValElem returns an iterator that produces the supplied value and error the supplied number of times. The same value and error will be returned so any modifications made to the value and error will be visible on subsiquent iterations. Any error other than nil will cause iteration to stop after the first value due to how the intermediaries and consumers are implemented.

func ValToPntr

func ValToPntr[T any](i Iter[T]) Iter[*T]

This function is an intermediary.

ValToPntr will map a stream of values to a stream of pointers to the values. ValToPntr will stop iteration if an error is returned from it's parent iterator regardless of if it has fully consumed it's input stream of values. ValToPntr will never be the cause of an error.

func Zip

func Zip[T any, U any](
	i1 Iter[T],
	i2 Iter[U],
	factory func() basic.Pair[T, U],
) Iter[basic.Pair[T, U]]

This function is a producer.

Zip will take two iterators and return an iterator that iterates over pairs of values where each pair contains a value from each supplied iterator. The number of values returned by this iterator will equal the number of elements from the supplied iterator that produces the least number values. Excess values will be ignored. Errors from the supplied iterators will be returned from this iterator.

func (Iter[T]) All

func (i Iter[T]) All(op func(val T) (bool, error)) (bool, error)

This function is a Consumer.

All will apply the supplied operation function (op) to each value from it's parent iterator and will only return true if the operation function returns true for every value, otherwise it will return false. If an error occurs iteration will stop. If an error occurs, the state of the boolean value that All returns will reflect the result of applying the operation function to every value from the parent iterator before the error occurred, excluding the value returned with the error.

func (Iter[T]) Any

func (i Iter[T]) Any(op func(val T) (bool, error)) (bool, error)

This function is a Consumer.

Any will apply the supplied operation function (op) to each value from it's parent iterator and will only return true if the operation function returns true for any value, otherwise it will return false. If an error occurs iteration will stop. If an error occurs, the state of the boolean value that Any returns will reflect the result of applying the operation function to every value from the parent iterator before the error occurred, excluding the value returned with the error.

func (Iter[T]) AppendTo

func (i Iter[T]) AppendTo(orig *[]T) (int, error)

This function is a Consumer.

AppendTo will append all of it's parent iterators values into a slice. Iteration will stop if an error occurs. If an error occurs then the slice will contain all the values that were already present in it plus the values that were received up until the error occurred.

func (Iter[T]) Collect

func (i Iter[T]) Collect() ([]T, error)

This function is a Consumer.

Collect will collect all of it's parent iterators values into a slice and return it. Iteration will stop if an error occurs. If an error occurs then the slice will contain all the values that were recieved up until that point.

func (Iter[T]) Consume

func (i Iter[T]) Consume() error

This function is a Consumer.

Consume will consume its parent iterators entirely, only stopping early if it hits an error. The values from the parent iterator are not saved or used in any way.

func (Iter[T]) Count

func (i Iter[T]) Count() (int, error)

This function is a Consumer.

Count will consumer it's parent iterator, counting the number of values that it receives. The values from the parent iterator are not saved or used in any way. Iteration will stop if an error occurs.

func (Iter[T]) Filter

func (i Iter[T]) Filter(op func(index int, val T) bool) Iter[T]

This function is an intermediary.

Filter will selectively pass on values from it's parent iterator to its child iterator based on the return value of the operatio (op) function. An error will stop iteration and be propogated to the child iterator regardless of the implementation of the operation function.

func (Iter[T]) FilterParallel

func (i Iter[T]) FilterParallel(op func(val T) bool, numThreads int) ([]T, error)

This funciton is a consumer.

This function will filter each value from it's parent iterator in parallel. The provided operation function will be run in parallel using numThreads go routines. The operation function will return true should return true if the value should be kept and false if it should not be kept. Use FilterParallel when the operation that determines which values to filter takes a non-trivial amount of time.

func (Iter[T]) Find

func (i Iter[T]) Find(op func(val T) (bool, error)) (T, error, bool)

This function is a Consumer.

Find will search for a value in it's parent iterators values using the supplied operation function (op) as an equality comparison. Find returns three values:

1. The value that was found 2. An error status that represents errors raised during iteration or from the equality comparison function. 3. A boolean value that indicates if the value was found or not.

If an error occurs iteration stops.

func (Iter[T]) ForEach

func (i Iter[T]) ForEach(
	op func(index int, val T) (IteratorFeedback, error),
) error

This funciton is a consumer.

For each will take values from it's parent iterator and perform the supplied operation function on each value, until an error occurs. If an error occurs the operation function is not called and iteration stops.

func (Iter[T]) Index

func (i Iter[T]) Index(op func(val T) (bool, error)) (int, error)

This function is a Consumer.

Index will search for a value in it's parent iterators values using the supplied operation function (op) as an equality comparison. The index of the value will be returned, or -1 if the value is not found. If an error occurs iteration will stop.

func (Iter[T]) Inject

func (i Iter[T]) Inject(
	op func(idx int, val T, injectedPrev bool) (T, error, bool),
) Iter[T]

This function is an intermediary.

Inject will inject values into the iterator stream based on the operation (op) functions return values. If the operation function returns true then the value will be injected and the parent iterators current value will be cached to be returned as soon as the operation function returns false. This provides a way to arbitrarily change the sequence of values that is output. If an error is returned from either the parent iterator or the operation function then iteration will stop.

func (Iter[T]) Map

func (i Iter[T]) Map(op func(index int, val T) (T, error)) Iter[T]

This function is an intermediary.

Map will create a mapping between two iterators of the same type. This is equivalent the calling the previous Map function and providing it with the same types. Iteration will stop if an error is generated.

func (Iter[T]) Next

func (i Iter[T]) Next(
	op func(index int, val T, status IteratorFeedback) (IteratorFeedback, T, error),
) Iter[T]

This function is an intermediary.

This function is equivalent to Next, the only difference is that the the inputs iterator type and output iterator type must be the same. It is offered as a convenience function.

func (Iter[T]) Nth

func (i Iter[T]) Nth(idx int) (T, error, bool)

This function is a Consumer.

Nth will return the value at the nth index from it's parent consumer. Nth returns three values:

1. The value that was found 2. An error status that represents errors raised during iteration 3. A boolean value that indicates if the nth index was reached or not

If an error occurs iteration will stop.

func (Iter[T]) Parallel

func (i Iter[T]) Parallel(
	workerOp func(val T) (T, error),
	resOp func(val T, res T, err error),
	numThreads int,
) error

This function is a consumer.

This function is equivalent to Parallel, the only difference is that the the inputs and outputs of the workers must be the same. It is offered as a convenience function.

func (Iter[T]) Pull

func (i Iter[T]) Pull(num int) ([]T, error, bool)

This function is a consumer.

Pull will pull num values from the iterator chain, until the end of the iterator chain has been reached. It will return the values, an error if one occurred while obtaining the values, and a boolean flag to indicate success. The values that is returned should be assumed to be valid, even if err is not nil or the boolean flag is false. This function *does not* clean up the iterator chain once the chains producer has reached the end of its stream of values. Stop must be called manually to do this. Continuing to call Pull after the end of the iterator stream has been reached will not result in any undefined behavior.

func (Iter[T]) PullOne

func (i Iter[T]) PullOne() (T, error, bool)

This function is a consumer.

PullOne will pull one value from the iterator chain. It will return the value, an error if one occurred while obtaining the value, and a boolean flag to indicate success. The value that is returned should be assumed to be invalid if err is not nil or the boolean flag is false. This function *does not* clean up the iterator chain once the chains producer has reached the end of its stream of values. Stop must be called manually to do this. Continuing to call PullOne after the end of the iterator stream has been reached will not result in any undefined behavior.

func (Iter[T]) Reduce

func (i Iter[T]) Reduce(start T, op func(accum *T, iter T) error) (T, error)

This function is a Consumer.

Reduce will take all of the values from it's parent iterator and will combine them using the logic from the operation function (op), returning the combined value. The start value is specified as an argument. If an error occurs then iteration will stop and the current accumulated value will be returned without applying the operation function to the value that returned an error.

func (Iter[T]) Setup

func (i Iter[T]) Setup(setup func() error) Iter[T]

This function is an intermediary.

Setup will call the provided setup function before it calls its parent iterator. The setup function will only be called once. An error returned from the setup function will stop iteration and the parent iterator will never be called.

func (Iter[T]) SetupTeardown

func (i Iter[T]) SetupTeardown(setup func() error, teardown func() error) Iter[T]

This function is an intermediary.

SetupTeardown provides a way to have setup and teardown procedures. These setup and teardown procedures will be called once before the parent iterator is ever called and after once after the parent iterator has completed. The teardown procedure will always be called even if the parent iterator returned an error.

func (Iter[T]) Skip

func (i Iter[T]) Skip(num int) Iter[T]

This function is an intermediary.

Skip will skip the first num elements of it's parent iterator before propagating any further elements to it's child iterator. Skip will stop iteration if an error is returned from it's parent iterator regardless of if it has reached num elements or not.

func (Iter[T]) Stop

func (i Iter[T]) Stop() error

This function is a consumer.

Stop will stop all iteration without ever consuming a single value from it's parent iterator. Any errors returned will be generated from each iterator performing there respective teardown operations.

func (Iter[T]) Take

func (i Iter[T]) Take(num int) Iter[T]

This function is an intermediary.

Take will consume the first num elements of it's parent iterator. It will stop iteraton after the first num elements have been consumed. If an error occurs iteraton will stop regardless of if num elements have been consumed.

func (Iter[T]) TakeWhile

func (i Iter[T]) TakeWhile(op func(val T) bool) Iter[T]

This function is an intermediary.

Take while will take elements while the supplied operation (op) returns true. Once the supplied operation returns false iteration will stop. If an error is returned from the parent iterator iteration will stop and the operation function will not be called on the value that errored.

func (Iter[T]) Teardown

func (i Iter[T]) Teardown(teardown func() error) Iter[T]

This function is an intermediary.

Teardown will call the provided teardown function once it's parent iterator has completed iteration. Teardown will only be called it iterator has started. If iteration never began due to an early error teardown will not be called. The teardown function will only be called once. An error returned from the teardown function will stop iteration.

func (Iter[T]) ToChan

func (i Iter[T]) ToChan(c chan T)

This function is a Consumer.

ToChan will take all the values from it's parent iterator and will push them to the specified channel. Errors are not propogated to the channel. Iteration will stop if an error occurs. This function will not close the channel that is supplied to it.

func (Iter[T]) ToWriter

func (i Iter[T]) ToWriter(src io.Writer, addNewLine bool) error

This function is a Consumer.

ToWriter will take all the values from it's parent iterator and will write them to the specified writer. All values are written to the writer using the standard fmt.Sprintf %v formatting directive. If you want a format other than that then map the values to the formatted string before passing values to this iterator.

If addNewLine is true then newlines will be appended to every value after it is formatted.

type IteratorFeedback

type IteratorFeedback int

A type that defines the valid states that an iterator chain can use.

const (
	Continue IteratorFeedback = iota // Signaling to continue iteration, consume the next value
	Break                            // Signaling to stop iteration. The current value is no longer valid.
	Iterate                          // Signaling to iterate again, get the next value from the iterator.
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL