Channels are useful, but closures are often more suitable.
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
// closure captures variable n
return func() int {
n += 2
return n
}
}
Playground: http://play.golang.org/p/W7pG_HUOzw
Don't like closures either? Use a named type with a method:
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)
}
Playground: http://play.golang.org/p/o0lerLcAh3
There are tradeoffs among the three techniques so you can't nominate one as idiomatic. Use whatever best meets your needs.
Chaining is easy because functions are first class objects. Here's an extension of the closure example. I added a type intGen for integer generator which makes it clear where generator functions are used as arguments and return values. mapInt is defined in a general way to map any integer function to an integer generator. Other functions such as filter and fold could be defined similarly.
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
}
Playground: http://play.golang.org/p/L1OFm6JuX0