Creating Iterators in Go: Channels vs. Closures vs. Named Types
In Go, various approaches exist for creating iterators. One popular option is utilizing channels that resemble iterators. However, channels suffer from limitations, particularly being a push model rather than a pull model, causing potential leaks.
An idiomatic approach involves employing closures. The following example demonstrates how to create an iterator for generating even numbers:
package main import "fmt" func main() { gen := newEven() fmt.Println(gen()) fmt.Println(gen()) fmt.Println(gen()) gen = nil // release for garbage collection } func newEven() func() int { n := 0 return func() int { n += 2 return n } }
Another option is using named types with methods:
package main import "fmt" func main() { gen := even(0) fmt.Println(gen.next()) fmt.Println(gen.next()) fmt.Println(gen.next()) } type even int func (e *even) next() int { *e += 2 return int(*e) }
The choice between closures and named types depends on specific needs. Closures provide flexibility, while named types may offer a more structured approach.
Additionally, chaining iterators is straightforward in Go due to functions being first-class objects. The following example chains a generator for even numbers with a square function:
package main import "fmt" func main() { gen := mapInt(newEven(), square) fmt.Println(gen()) fmt.Println(gen()) fmt.Println(gen()) gen = nil // release for garbage collection } type intGen func() int func newEven() intGen { n := 0 return func() int { n += 2 return n } } func mapInt(g intGen, f func(int) int) intGen { return func() int { return f(g()) } } func square(i int) int { return i * i }
The above is the detailed content of What's the Best Way to Create Iterators in Go: Channels, Closures, or Named Types?. For more information, please follow other related articles on the PHP Chinese website!