# Generators in Go

**Sven Haardiek, 2020-07-24**

Lately I played a lot with Haskell and I started to love lazy evaluation as it let me define infinite sequences without the need of infinite memory.

But at work, I mostly write programs using Python and Go.

Python’s nearest thing to lazy evaluation are Iterators and especially Generators in my opinion and they are great.

You can write a function, just like you would do normally, and instead of a
return, you `yield`

the next generated value on each call, like shown
here.

```
def fibonacci(limit):
a, b = 0, 1
for _ in range(limit):
yield a
a, b = b, a+b
for number in fibonacci(100): # The generator constructs an iterator
print(number)
```

So now I thought: *Hej, what about Go? How should I write generators there?* So
I tried some different approaches to write generators for Fibonacci
numbers and I want to share them
here.

## Native Approach

So let’s dive directly into it. What do we need for an Generator? We need a struct to store our current state in and we need a function which returns the next Fibonacci value. Okay that should be pretty simple. Let’s take a look.

```
type fibonacci struct {
a, b int
}
func (f *fibonacci) Next() int {
r := f.a
f.a, f.b = f.a+f.b, f.a
return r
}
```

Now our struct is holding the last two values, which are needed to calculate
the next Fibonacci number. Also `Next`

should return the next Fibonacci number
on every call. Let’s check, if it is working with the following code.

```
func main() {
f := fibonacci{0, 1}
for i := 0; i < 20; i++ {
fmt.Printf("%v ", f.Next())
}
}
```

If we now run this code, we get ```
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610
987 1597 2584 4181
```

– mission accomplished.

Our code looks nearly the same than the Python code we posted early, but we had
to cache the result, since we not `yield`

, but just call the whole function
again.
Also there is a limit in the Python code – we want that in our Go code too.
So let’s implement it.

Our struct is now also holding a `limit`

and we have to change the return value
of our `Next`

function, since we need to have an indicator when there are no
values left.

```
type fibonacci struct {
a, b, limit int
}
func (f *fibonacci) Next() *int {
if f.limit == 0 {
return nil
}
r := f.a
f.a, f.b = f.b, f.a+f.b
f.limit--
return &r
}
```

Now the limit is stored in the generator itself. So we can change our `main`

to

```
func main() {
f := fibonacci{0, 1, 20}
for {
r := f.Next()
if r == nil {
return
}
fmt.Printf("%v ", *r)
}
}
```

If we run this, we get ```
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
2584 4181
```

, which is looking exactly like the result we were expecting.

Until now there were not many surprises. Writing generators like this, can be done in nearly any language.

## Channels

One cool thing about the generator in Python is that there is no constructor and we can simply iterate over it. In Go we can achieve the same thing with channels. Let’s take a look.

```
func fibonacci(limit int) chan int {
c := make(chan int)
a := 0
b := 1
go func() {
for {
if limit == 0 {
close(c)
return
}
c <- a
a, b = b, a+b
limit--
}
}()
return c
}
```

Instead of `yield`

we write into the channel and block until someone reads the
value. After that we continue after the write, which is really similar to the
`yield`

from Python.

Also this function is returning a `chan int`

, so we can directly iterate over
it.

```
func main() {
for r := range fibonacci(20) {
fmt.Printf("%v ", r)
}
}
```

If we run this, we get again ```
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
1597 2584 4181
```

.

Now we have replicated the behaviour of generators in python already pretty closely, except one detail: the Next functionality. Because sometime we might want to iterate over the function, but in other cases we might want to call Next. Let’s try to combine these two approaches.

## Combination

The idea here is to create an object and connect a `Next`

function to it, but
also be able to iterate over the object itself. Okay, let’s take a look.

```
type fibonacciChan chan int
func (f fibonacciChan) Next() *int {
c, ok := <-f
if !ok {
return nil
}
return &c
}
```

Cool. Now we can call `Next`

on our object and get the next result from the
channel and `nil`

, if it is closed. Now we only have to adapt our `fibonacci`

function to return a `fibonacciChan`

.

```
func fibonacci(limit int) fibonacciChan {
c := make(chan int)
a := 0
b := 1
go func() {
for {
if limit == 0 {
close(c)
return
}
c <- a
a, b = b, a+b
limit--
}
}()
return c
}
```

Let’s try to to either call `Next`

or to iterate with this code.

```
func main() {
f := fibonacci(20)
fmt.Printf("%v ", *f.Next())
fmt.Printf("%v ", *f.Next())
for r := range f {
fmt.Printf("%v ", r)
}
}
```

If you execute it, you get again ```
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
610 987 1597 2584 4181
```

.

## Conclusion

So now you hopefully have a better understanding about generators in Go. You can also find the code on GitHub. If you have further questions or comments drop me a mail.

Happy hacking!