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