HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoMajor

Fibonacci generator with Golang

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withgolangfibonaccigenerator

Problem

This is my Fibonacci generator:

package main

import "fmt"

func main() {
    for i, j := 0, 1; j < 100; i, j = i+j,i {
        fmt.Println(i)
    }
}


It's working, but I don't know how I can improve it, so I'd like more expert approaches to solving it.

Solution

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

Code Snippets

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
}
go func() { ... }()
func main() {
    c := fib_generator()
    for n := 0; n < 12 ; n++ {
        fmt.Println(<- c)
    }
}
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()
}
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

Context

StackExchange Code Review Q#28386, answer score: 20

Revisions (0)

No revisions yet.