github.com/m4gshm/gollections@v0.0.10/loop/api.go (about) 1 // Package loop provides helpers for loop operation and iterator implementations 2 package loop 3 4 import ( 5 "golang.org/x/exp/constraints" 6 7 "github.com/m4gshm/gollections/break/loop" 8 breakAlways "github.com/m4gshm/gollections/break/predicate/always" 9 "github.com/m4gshm/gollections/c" 10 "github.com/m4gshm/gollections/convert" 11 "github.com/m4gshm/gollections/convert/as" 12 "github.com/m4gshm/gollections/map_/resolv" 13 "github.com/m4gshm/gollections/notsafe" 14 "github.com/m4gshm/gollections/op" 15 "github.com/m4gshm/gollections/op/check/not" 16 "github.com/m4gshm/gollections/predicate/always" 17 ) 18 19 // ErrBreak is the 'break' statement of the For, Track methods 20 var ErrBreak = c.ErrBreak 21 22 // Looper provides an iterable loop function 23 type Looper[T any, I interface{ Next() (T, bool) }] interface { 24 Loop() I 25 } 26 27 // Of wrap the elements by loop function 28 func Of[T any](elements ...T) func() (e T, ok bool) { 29 l := len(elements) 30 i := 0 31 if l == 0 || i < 0 || i >= l { 32 return func() (e T, ok bool) { return e, false } 33 } 34 return func() (e T, ok bool) { 35 if i < l { 36 e, ok = elements[i], true 37 i++ 38 } 39 return e, ok 40 } 41 } 42 43 // For applies the 'walker' function for the elements retrieved by the 'next' function. Return the c.ErrBreak to stop 44 func For[T any](next func() (T, bool), walker func(T) error) error { 45 for v, ok := next(); ok; v, ok = next() { 46 if err := walker(v); err == ErrBreak { 47 return nil 48 } else if err != nil { 49 return err 50 } 51 } 52 return nil 53 } 54 55 // ForEach applies the 'walker' function to the elements retrieved by the 'next' function 56 func ForEach[T any](next func() (T, bool), walker func(T)) { 57 for v, ok := next(); ok; v, ok = next() { 58 walker(v) 59 } 60 } 61 62 // ForEachFiltered applies the 'walker' function to the elements retrieved by the 'next' function that satisfy the 'predicate' function condition 63 func ForEachFiltered[T any](next func() (T, bool), predicate func(T) bool, walker func(T)) { 64 for v, ok := next(); ok; v, ok = next() { 65 if predicate(v) { 66 walker(v) 67 } 68 } 69 } 70 71 // First returns the first element that satisfies the condition of the 'predicate' function 72 func First[T any](next func() (T, bool), predicate func(T) bool) (v T, ok bool) { 73 for one, ok := next(); ok; one, ok = next() { 74 if predicate(one) { 75 return one, true 76 } 77 } 78 return v, ok 79 } 80 81 // Track applies the 'tracker' function to position/element pairs retrieved by the 'next' function. Return the c.ErrBreak to stop tracking.. 82 func Track[I, T any](next func() (I, T, bool), tracker func(I, T) error) error { 83 for p, v, ok := next(); ok; p, v, ok = next() { 84 if err := tracker(p, v); err == ErrBreak { 85 return nil 86 } else if err != nil { 87 return err 88 } 89 } 90 return nil 91 } 92 93 // TrackEach applies the 'tracker' function to position/element pairs retrieved by the 'next' function 94 func TrackEach[I, T any](next func() (I, T, bool), tracker func(I, T)) { 95 for p, v, ok := next(); ok; p, v, ok = next() { 96 tracker(p, v) 97 } 98 } 99 100 // Slice collects the elements retrieved by the 'next' function into a new slice 101 func Slice[T any](next func() (T, bool)) []T { 102 return SliceCap(next, 0) 103 } 104 105 // SliceCap collects the elements retrieved by the 'next' function into a new slice with predefined capacity 106 func SliceCap[T any](next func() (T, bool), cap int) (out []T) { 107 if cap > 0 { 108 out = make([]T, 0, cap) 109 } 110 return Append(next, out) 111 } 112 113 // Append collects the elements retrieved by the 'next' function into the specified 'out' slice 114 func Append[T any, TS ~[]T](next func() (T, bool), out TS) TS { 115 for v, ok := next(); ok; v, ok = next() { 116 out = append(out, v) 117 } 118 return out 119 } 120 121 // Reduce reduces the elements retrieved by the 'next' function into an one using the 'merger' function 122 func Reduce[T any](next func() (T, bool), merger func(T, T) T) (result T) { 123 if v, ok := next(); ok { 124 result = v 125 } else { 126 return result 127 } 128 for v, ok := next(); ok; v, ok = next() { 129 result = merger(result, v) 130 } 131 return result 132 } 133 134 // Sum returns the sum of all elements 135 func Sum[T c.Summable](next func() (T, bool)) T { 136 return Reduce(next, op.Sum[T]) 137 } 138 139 // HasAny finds the first element that satisfies the 'predicate' function condition and returns true if successful 140 func HasAny[T any](next func() (T, bool), predicate func(T) bool) bool { 141 _, ok := First(next, predicate) 142 return ok 143 } 144 145 // Contains finds the first element that equal to the example and returns true 146 func Contains[T comparable](next func() (T, bool), example T) bool { 147 for one, ok := next(); ok; one, ok = next() { 148 if one == example { 149 return true 150 } 151 } 152 return false 153 } 154 155 // Conv instantiates an iterator that converts elements with a converter and returns them. 156 func Conv[From, To any](next func() (From, bool), converter func(From) (To, error)) loop.ConvertIter[From, To] { 157 return loop.Conv(loop.From(next), converter) 158 } 159 160 // Convert instantiates an iterator that converts elements with a converter and returns them. 161 func Convert[From, To any](next func() (From, bool), converter func(From) To) ConvertIter[From, To] { 162 return ConvertIter[From, To]{next: next, converter: converter} 163 } 164 165 // ConvCheck is similar to ConvertFilt, but it checks and transforms elements together 166 func ConvCheck[From, To any](next func() (From, bool), converter func(from From) (To, bool, error)) loop.ConvertCheckIter[From, To] { 167 return loop.ConvCheck(loop.From(next), converter) 168 } 169 170 // ConvertCheck is similar to ConvertFilt, but it checks and transforms elements together 171 func ConvertCheck[From, To any](next func() (From, bool), converter func(from From) (To, bool)) ConvertCheckIter[From, To] { 172 return ConvertCheckIter[From, To]{next: next, converter: converter} 173 } 174 175 // FiltAndConv returns a stream that filters source elements and converts them 176 func FiltAndConv[From, To any](next func() (From, bool), filter func(From) (bool, error), converter func(From) (To, error)) loop.ConvFiltIter[From, To] { 177 return loop.FiltAndConv(loop.From(next), filter, converter) 178 } 179 180 // FilterAndConvert returns a stream that filters source elements and converts them 181 func FilterAndConvert[From, To any](next func() (From, bool), filter func(From) bool, converter func(From) To) ConvertFiltIter[From, To] { 182 return FilterConvertFilter(next, filter, converter, always.True[To]) 183 } 184 185 // FilterConvertFilter filters source, converts, and filters converted elements 186 func FilterConvertFilter[From, To any](next func() (From, bool), filter func(From) bool, converter func(From) To, filterTo func(To) bool) ConvertFiltIter[From, To] { 187 return ConvertFiltIter[From, To]{next: next, converter: converter, filterFrom: filter, filterTo: filterTo} 188 } 189 190 // ConvertAndFilter additionally filters 'To' elements 191 func ConvertAndFilter[From, To any](next func() (From, bool), converter func(From) To, filter func(To) bool) ConvertFiltIter[From, To] { 192 return FilterConvertFilter(next, always.True[From], converter, filter) 193 } 194 195 // Flatt instantiates an iterator that extracts slices of 'To' by a flattener from elements of 'From' and flattens as one iterable collection of 'To' elements. 196 func Flatt[From, To any](next func() (From, bool), flattener func(From) ([]To, error)) *loop.FlatIter[From, To] { 197 return loop.Flatt(loop.From(next), flattener) 198 } 199 200 // Flat instantiates an iterator that extracts slices of 'To' by a flattener from elements of 'From' and flattens as one iterable collection of 'To' elements. 201 func Flat[From, To any](next func() (From, bool), flattener func(From) []To) *FlatIter[From, To] { 202 return &FlatIter[From, To]{next: next, flattener: flattener, elemSizeTo: notsafe.GetTypeSize[To]()} 203 } 204 205 // FiltAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function 206 func FiltAndFlat[From, To any](next func() (From, bool), filter func(From) (bool, error), flattener func(From) ([]To, error)) *loop.FlattFiltIter[From, To] { 207 return loop.FiltFlattFilt(loop.From(next), filter, flattener, breakAlways.True[To]) 208 } 209 210 // FilterAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function 211 func FilterAndFlat[From, To any](next func() (From, bool), filter func(From) bool, flattener func(From) []To) *FlatFilterIter[From, To] { 212 return FilterFlatFilter(next, filter, flattener, always.True[To]) 213 } 214 215 // FlatAndFilt extracts slices of 'To' by the 'flattener' function and filters extracted elements 216 func FlatAndFilt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) *loop.FlattFiltIter[From, To] { 217 return loop.FiltFlattFilt(next, breakAlways.True[From], flattener, filterTo) 218 } 219 220 // FlattAndFilter extracts slices of 'To' by the 'flattener' function and filters extracted elements 221 func FlattAndFilter[From, To any](next func() (From, bool), flattener func(From) []To, filterTo func(To) bool) *FlatFilterIter[From, To] { 222 return FilterFlatFilter(next, always.True[From], flattener, filterTo) 223 } 224 225 // FiltFlattFilt filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements 226 func FiltFlattFilt[From, To any](next func() (From, bool), filterFrom func(From) (bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) *loop.FlattFiltIter[From, To] { 227 return loop.FiltFlattFilt(loop.From(next), filterFrom, flattener, filterTo) 228 } 229 230 // FilterFlatFilter filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements 231 func FilterFlatFilter[From, To any](next func() (From, bool), filterFrom func(From) bool, flattener func(From) []To, filterTo func(To) bool) *FlatFilterIter[From, To] { 232 return &FlatFilterIter[From, To]{next: next, filterFrom: filterFrom, flattener: flattener, filterTo: filterTo, elemSizeTo: notsafe.GetTypeSize[To]()} 233 } 234 235 // Filt creates an iterator that checks elements by the 'filter' function and returns successful ones. 236 func Filt[T any](next func() (T, bool), filter func(T) (bool, error)) loop.FiltIter[T] { 237 return loop.Filt(loop.From(next), filter) 238 } 239 240 // Filter creates an iterator that checks elements by the 'filter' function and returns successful ones. 241 func Filter[T any](next func() (T, bool), filter func(T) bool) FiltIter[T] { 242 return FiltIter[T]{next: next, by: filter} 243 } 244 245 // NotNil creates an iterator that filters nullable elements 246 func NotNil[T any](next func() (*T, bool)) FiltIter[*T] { 247 return Filter(next, not.Nil[T]) 248 } 249 250 // PtrVal creates an iterator that transform pointers to the values referenced by those pointers. 251 // Nil pointers are transformet to zero values. 252 func PtrVal[T any](next func() (*T, bool)) ConvertIter[*T, T] { 253 return Convert(next, convert.PtrVal[T]) 254 } 255 256 // NoNilPtrVal creates an iterator that transform only not nil pointers to the values referenced referenced by those pointers. 257 // Nil pointers are ignored. 258 func NoNilPtrVal[T any](next func() (*T, bool)) ConvertCheckIter[*T, T] { 259 return ConvertCheck(next, convert.NoNilPtrVal[T]) 260 } 261 262 // KeyValue transforms iterable elements to key/value iterator based on applying key, value extractors to the elements 263 func KeyValue[T any, K, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) KeyValuer[T, K, V] { 264 return NewKeyValuer(next, keyExtractor, valExtractor) 265 } 266 267 // KeyValuee transforms iterable elements to key/value iterator based on applying key, value extractors to the elements 268 func KeyValuee[T any, K, V any](next func() (T, bool), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) loop.KeyValuer[T, K, V] { 269 return loop.KeyValuee(loop.From(next), keyExtractor, valExtractor) 270 } 271 272 // KeysValues transforms iterable elements to key/value iterator based on applying multiple keys, values extractor to the elements 273 func KeysValues[T, K, V any](next func() (T, bool), keysExtractor func(T) []K, valsExtractor func(T) []V) *MultipleKeyValuer[T, K, V] { 274 return NewMultipleKeyValuer(next, keysExtractor, valsExtractor) 275 } 276 277 // KeysValue transforms iterable elements to key/value iterator based on applying keys, value extractor to the elements 278 func KeysValue[T, K, V any](next func() (T, bool), keysExtractor func(T) []K, valExtractor func(T) V) *MultipleKeyValuer[T, K, V] { 279 return KeysValues(next, keysExtractor, func(t T) []V { return convert.AsSlice(valExtractor(t)) }) 280 } 281 282 // KeysValuee transforms iterable elements to key/value iterator based on applying keys, value extractor to the elements 283 func KeysValuee[T, K, V any](next func() (T, bool), keysExtractor func(T) ([]K, error), valExtractor func(T) (V, error)) *loop.MultipleKeyValuer[T, K, V] { 284 return loop.KeysValuee(loop.From(next), keysExtractor, valExtractor) 285 } 286 287 // KeyValues transforms iterable elements to key/value iterator based on applying key, values extractor to the elements 288 func KeyValues[T, K, V any](next func() (T, bool), keyExtractor func(T) K, valsExtractor func(T) []V) *MultipleKeyValuer[T, K, V] { 289 return KeysValues(next, func(t T) []K { return convert.AsSlice(keyExtractor(t)) }, valsExtractor) 290 } 291 292 // KeyValuess transforms iterable elements to key/value iterator based on applying key, values extractor to the elements 293 func KeyValuess[T, K, V any](next func() (T, bool), keyExtractor func(T) (K, error), valsExtractor func(T) ([]V, error)) *loop.MultipleKeyValuer[T, K, V] { 294 return loop.KeyValuess(loop.From(next), keyExtractor, valsExtractor) 295 } 296 297 // ExtraVals transforms iterable elements to key/value iterator based on applying values extractor to the elements 298 func ExtraVals[T, V any](next func() (T, bool), valsExtractor func(T) []V) *MultipleKeyValuer[T, T, V] { 299 return KeyValues(next, as.Is[T], valsExtractor) 300 } 301 302 // ExtraValss transforms iterable elements to key/value iterator based on applying values extractor to the elements 303 func ExtraValss[T, V any](next func() (T, bool), valsExtractor func(T) ([]V, error)) *loop.MultipleKeyValuer[T, T, V] { 304 return KeyValuess(next, as.ErrTail(as.Is[T]), valsExtractor) 305 } 306 307 // ExtraKeys transforms iterable elements to key/value iterator based on applying key extractor to the elements 308 func ExtraKeys[T, K any](next func() (T, bool), keysExtractor func(T) []K) *MultipleKeyValuer[T, K, T] { 309 return KeysValue(next, keysExtractor, as.Is[T]) 310 } 311 312 // ExtraKeyss transforms iterable elements to key/value iterator based on applying key extractor to the elements 313 func ExtraKeyss[T, K any](next func() (T, bool), keyExtractor func(T) (K, error)) *loop.MultipleKeyValuer[T, K, T] { 314 return KeyValuess(next, keyExtractor, as.ErrTail(convert.AsSlice[T])) 315 } 316 317 // ExtraKey transforms iterable elements to key/value iterator based on applying key extractor to the elements 318 func ExtraKey[T, K any](next func() (T, bool), keysExtractor func(T) K) KeyValuer[T, K, T] { 319 return KeyValue(next, keysExtractor, as.Is[T]) 320 } 321 322 // ExtraKeyy transforms iterable elements to key/value iterator based on applying key extractor to the elements 323 func ExtraKeyy[T, K any](next func() (T, bool), keyExtractor func(T) (K, error)) loop.KeyValuer[T, K, T] { 324 return loop.KeyValuee[T, K](loop.From(next), keyExtractor, as.ErrTail(as.Is[T])) 325 } 326 327 // ExtraValue transforms iterable elements to key/value iterator based on applying value extractor to the elements 328 func ExtraValue[T, V any](next func() (T, bool), valueExtractor func(T) V) KeyValuer[T, T, V] { 329 return KeyValue(next, as.Is[T], valueExtractor) 330 } 331 332 // ExtraValuee transforms iterable elements to key/value iterator based on applying value extractor to the elements 333 func ExtraValuee[T, V any](next func() (T, bool), valExtractor func(T) (V, error)) loop.KeyValuer[T, T, V] { 334 return loop.KeyValuee[T, T, V](loop.From(next), as.ErrTail(as.Is[T]), valExtractor) 335 } 336 337 // Group converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'. 338 // The keyExtractor converts an element to a key. 339 // The valExtractor converts an element to an value. 340 func Group[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) map[K][]V { 341 return ToMapResolv(next, keyExtractor, valExtractor, resolv.Append[K, V]) 342 } 343 344 // Groupp converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'. 345 // The keyExtractor converts an element to a key. 346 // The valExtractor converts an element to an value. 347 func Groupp[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) (map[K][]V, error) { 348 return loop.Groupp(loop.From(next), keyExtractor, valExtractor) 349 } 350 351 // GroupByMultiple converts elements retrieved by the 'next' function into a map, extracting multiple keys, values per each element applying the 'keysExtractor' and 'valsExtractor' functions. 352 // The keysExtractor retrieves one or more keys per element. 353 // The valsExtractor retrieves one or more values per element. 354 func GroupByMultiple[T any, K comparable, V any](next func() (T, bool), keysExtractor func(T) []K, valsExtractor func(T) []V) map[K][]V { 355 groups := map[K][]V{} 356 for e, ok := next(); ok; e, ok = next() { 357 if keys, vals := keysExtractor(e), valsExtractor(e); len(keys) == 0 { 358 var key K 359 for _, v := range vals { 360 initGroup(key, v, groups) 361 } 362 } else { 363 for _, key := range keys { 364 if len(vals) == 0 { 365 var v V 366 initGroup(key, v, groups) 367 } else { 368 for _, v := range vals { 369 initGroup(key, v, groups) 370 } 371 } 372 } 373 } 374 } 375 return groups 376 } 377 378 // GroupByMultipleKeys converts elements retrieved by the 'next' function into a map, extracting multiple keys, one value per each element applying the 'keysExtractor' and 'valExtractor' functions. 379 // The keysExtractor retrieves one or more keys per element. 380 // The valExtractor converts an element to a value. 381 func GroupByMultipleKeys[T any, K comparable, V any](next func() (T, bool), keysExtractor func(T) []K, valExtractor func(T) V) map[K][]V { 382 groups := map[K][]V{} 383 for e, ok := next(); ok; e, ok = next() { 384 if keys, v := keysExtractor(e), valExtractor(e); len(keys) == 0 { 385 var key K 386 initGroup(key, v, groups) 387 } else { 388 for _, key := range keys { 389 initGroup(key, v, groups) 390 } 391 } 392 } 393 return groups 394 } 395 396 // GroupByMultipleValues converts elements retrieved by the 'next' function into a map, extracting one key, multiple values per each element applying the 'keyExtractor' and 'valsExtractor' functions. 397 // The keyExtractor converts an element to a key. 398 // The valsExtractor retrieves one or more values per element. 399 func GroupByMultipleValues[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valsExtractor func(T) []V) map[K][]V { 400 groups := map[K][]V{} 401 for e, ok := next(); ok; e, ok = next() { 402 if key, vals := keyExtractor(e), valsExtractor(e); len(vals) == 0 { 403 var v V 404 initGroup(key, v, groups) 405 } else { 406 for _, v := range vals { 407 initGroup(key, v, groups) 408 } 409 } 410 } 411 return groups 412 } 413 414 func initGroup[T any, K comparable, TS ~[]T](key K, e T, groups map[K]TS) { 415 groups[key] = append(groups[key], e) 416 } 417 418 // ToMap collects key\value elements to a map by iterating over the elements 419 func ToMap[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) map[K]V { 420 return ToMapResolv(next, keyExtractor, valExtractor, resolv.First[K, V]) 421 } 422 423 // ToMapp collects key\value elements to a map by iterating over the elements 424 func ToMapp[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) (map[K]V, error) { 425 return loop.ToMapp(loop.From(next), keyExtractor, valExtractor) 426 } 427 428 // ToMapResolv collects key\value elements to a map by iterating over the elements with resolving of duplicated key values 429 func ToMapResolv[T any, K comparable, V, VR any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V, resolver func(bool, K, VR, V) VR) map[K]VR { 430 m := map[K]VR{} 431 for e, ok := next(); ok; e, ok = next() { 432 k, v := keyExtractor(e), valExtractor(e) 433 exists, ok := m[k] 434 m[k] = resolver(ok, k, exists, v) 435 } 436 return m 437 } 438 439 // New makes a loop from an abstract source 440 func New[S, T any](source S, hasNext func(S) bool, getNext func(S) T) func() (T, bool) { 441 return func() (out T, ok bool) { 442 if hasNext(source) { 443 out, ok = getNext(source), true 444 } 445 return out, ok 446 } 447 } 448 449 // RangeClosed creates a loop that generates integers in the range defined by from and to inclusive 450 func RangeClosed[T constraints.Integer](from T, toInclusive T) func() (T, bool) { 451 amount := toInclusive - from 452 delta := T(1) 453 if amount < 0 { 454 amount = -amount 455 delta = -delta 456 } 457 amount++ 458 nextElement := from 459 i := T(0) 460 return func() (out T, ok bool) { 461 if ok = i < amount; ok { 462 out = nextElement 463 i++ 464 nextElement = nextElement + delta 465 } 466 return out, ok 467 } 468 } 469 470 // Range creates a loop that generates integers in the range defined by from and to exclusive 471 func Range[T constraints.Integer](from T, toExclusive T) func() (T, bool) { 472 amount := toExclusive - from 473 delta := T(1) 474 if amount < 0 { 475 amount = -amount 476 delta = -delta 477 } 478 nextElement := from 479 i := T(0) 480 return func() (out T, ok bool) { 481 if ok = i < amount; ok { 482 out = nextElement 483 i++ 484 nextElement = nextElement + delta 485 } 486 return out, ok 487 } 488 } 489 490 // OfIndexed builds a loop by extracting elements from an indexed soruce. 491 // the len is length ot the source. 492 // the getAt retrieves an element by its index from the source. 493 func OfIndexed[T any](len int, next func(int) T) func() (T, bool) { 494 i := 0 495 return func() (out T, ok bool) { 496 if ok = i < len; ok { 497 out = next(i) 498 i++ 499 } 500 return out, ok 501 } 502 } 503 504 // ConvertAndReduce converts each elements and merges them into one 505 func ConvertAndReduce[From, To any](next func() (From, bool), converter func(From) To, merger func(To, To) To) (out To) { 506 if v, ok := next(); ok { 507 out = converter(v) 508 } else { 509 return out 510 } 511 for v, ok := next(); ok; v, ok = next() { 512 out = merger(out, converter(v)) 513 } 514 return out 515 } 516 517 // ConvAndReduce converts each elements and merges them into one 518 func ConvAndReduce[From, To any](next func() (From, bool), converter func(From) (To, error), merger func(To, To) To) (out To, err error) { 519 if v, ok := next(); ok { 520 out, err = converter(v) 521 if err != nil { 522 return out, err 523 } 524 } else { 525 return out, nil 526 } 527 for v, ok := next(); ok; v, ok = next() { 528 c, err := converter(v) 529 if err != nil { 530 return out, err 531 } 532 out = merger(out, c) 533 } 534 return out, nil 535 } 536 537 // Start is used with for loop construct like 'for i, k, v, ok := i.Start(); ok; k, v, ok = i.Next() { }' 538 func Start[T any](next func() (T, bool)) (func() (T, bool), T, bool) { 539 element, ok := next() 540 return next, element, ok 541 }