Your code is quite nice, and can't really be improved. However, let's put the “generator” back into the code.
Go has channels which can be used to write elegant generators/iterators. We spawn of a goroutine that fills the channel with the fibonacci sequence. The main thread then takes as many fibonacci numbers as it needs.
So let's write a function fib_generator
that returns a channel to the fibonacci sequence:
func fib_generator() chan int {
c := make(chan int)
go func() {
for i, j := 0, 1; ; i, j = i+j,i {
c <- i
}
}()
return c
}
We return a chan int
. Here, we use an unbuffered channel. You may want to introduce a bit of buffering, e.g. make(chan int, 7)
.
Next, we spawn a goroutine. This contains your code, but instead of printing the numbers, we fill the channel with them. Note that the generator does not have a termination condition.
The unusual syntax
go func() { ... }()
is the standard way to start a goroutine. Because the function literal is a closure over the channel c
, we can run multiple generators concurrently.
Our main
will look like
func main() {
c := fib_generator()
for n := 0; n < 12 ; n++ {
fmt.Println(<- c)
}
}
That is, we create a new generator, and then pull the first 12 values from the channel. We cannot write for i := range c { ... }
, because the fibonacci generator does not terminate.
As I said, we can have multiple generators concurrently:
func main() {
c1 := fib_generator()
c2 := fib_generator()
// read first 12 numbers from 1st channel
for n := 0; n < 10 ; n++ { fmt.Print(" ", <- c1) }
fmt.Println()
// read first 12 numbers from 2nd channel. The same.
for n := 0; n < 10 ; n++ { fmt.Print(" ", <- c2) }
fmt.Println()
// read next 5 numbers from 1st channel.
for n := 0; n < 5 ; n++ { fmt.Print(" ", <- c1) }
fmt.Println()
}
Output:
0 1 1 2 3 5 8 13 21 34
0 1 1 2 3 5 8 13 21 34
55 89 144 233 377