// All returns an iterator, which in Go is a function with a special signature.func (lst *List[T]) All() iter.Seq[T] { return func(yield func(T) bool) { // The iterator function takes another function called yield. // It will call yield for every element we want to iterate over, // and note yield's return value for potential early termination. for e := lst.head; e != nil; e = e.next { if !yield(e.val) { return } } }}
An iterator in Go is a function with the signature func(yield func(T) bool). The iter.Seq[T] type from the standard library defines this signature.
func main() { lst := List[int]{} lst.Push(10) lst.Push(13) lst.Push(23) // Since List.All returns an iterator, we can use it in a regular range loop. for e := range lst.All() { fmt.Println(e) } // Packages like slices have utilities for working with iterators. // Collect takes any iterator and collects all its values into a slice. all := slices.Collect(lst.All()) fmt.Println("all:", all)}
Iteration doesn’t require an underlying data structure and doesn’t even have to be finite:
// genFib returns an iterator over Fibonacci numbers.// It keeps running as long as yield keeps returning true.func genFib() iter.Seq[int] { return func(yield func(int) bool) { a, b := 0, 1 for { if !yield(a) { return } a, b = b, a+b } }}func main() { for n := range genFib() { // Once the loop hits break or an early return, // the yield function will return false. if n >= 10 { break } fmt.Println(n) }}
// Standard library packages expose iterator helpers.// For example, strings.SplitSeq iterates over parts without// first building a result slice.for part := range strings.SplitSeq("go-by-example", "-") { fmt.Printf("part: %s\n", part)}