1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
package iter
import "errors"
// Error returned from Iterator.Next() when iteration is done.
var FINISHED = errors.New("FINISHED")
// Iterator letting you specify just two functions defining iteration. All
// helper functions utilize this.
//
// Iterator is designed to avoid common pitfalls and to allow common Go patterns:
// - errors can be yielded all the way up the chain to the caller
// - safe iteration in background channels
// - iterators are nil-clean (you can send nil values through the iterator)
// - allows for cleanup when iteration ends early
type Iterator struct {
// Get the next value (or error).
// nil, iter.FINISHED indicates iteration is complete.
Next func() (interface{}, error)
// Close out resources in case iteration terminates early. Callers are *not*
// required to call this if iteration completes cleanly (but they may).
Close func()
}
// Use to create an iterator from a single closure. retun nil to stop iteration.
//
// iter.NewSimple(func() interface{} { return x*2 })
func NewSimple(f func() interface{}) Iterator {
return Iterator{
Next: func() (interface{}, error) {
val := f()
if val == nil {
return nil, FINISHED
} else {
return f, nil
}
},
Close: func() {},
}
}
// Transform values in the input.
// iterator.Map(func(item interface{}) interface{} { item.(int) * 2 })
func (iterator Iterator) Map(mapper func(interface{}) interface{}) Iterator {
return Iterator{
Next: func() (interface{}, error) {
item, err := iterator.Next()
if err != nil {
return nil, err
}
return mapper(item), nil
},
Close: func() { iterator.Close() },
}
}
// Filter values from the input.
// iterator.Select(func(item interface{}) bool { item.(int) > 10 })
func (iterator Iterator) Select(selector func(interface{}) bool) Iterator {
return Iterator{
Next: func() (interface{}, error) {
for {
item, err := iterator.Next()
if err != nil {
return nil, err
}
if selector(item) {
return item, nil
}
}
},
Close: func() { iterator.Close() },
}
}
// Concatenate multiple iterators together in one.
// d := iter.Concat(a, b, c)
func Concat(iterators ...Iterator) Iterator {
i := 0
return Iterator{
Next: func() (interface{}, error) {
if i >= len(iterators) {
return nil, FINISHED
}
item, err := iterators[i].Next()
if err == FINISHED {
i++
return nil, err
} else if err != nil {
i = len(iterators)
return nil, err
}
return item, nil
},
Close: func() {
// Close out remaining iterators
for ; i < len(iterators); i++ {
iterators[i].Close()
}
},
}
}
// Iterate over all values, calling a user-defined function for each one.
// iterator.Each(func(item interface{}) { fmt.Println(item) })
func (iterator Iterator) Each(processor func(interface{})) error {
defer iterator.Close()
item, err := iterator.Next()
for err == nil {
processor(item)
item, err = iterator.Next()
}
return err
}
// Iterate over all values, calling a user-defined function for each one.
// If an error is returned from the function, iteration terminates early
// and the EachWithError function returns the error.
// iterator.EachWithError(func(item interface{}) error { return http.Get(item.(string)) })
func (iterator Iterator) EachWithError(processor func(interface{}) error) error {
defer iterator.Close()
item, err := iterator.Next()
for err == nil {
err = processor(item)
if err == nil {
item, err = iterator.Next()
}
}
return err
}
// Convert the iteration directly to a slice.
// var list []interface{}
// list, err := iterator.ToSlice()
func (iterator Iterator) ToSlice() (list []interface{}, err error) {
err = iterator.Each(func(item interface{}) {
list = append(list, item)
})
return list, err
}
|