Go Closures
Let's continue with advanced topics about functions. In Go, a closure is a special kind of function that can access variables from the surrounding scope.
The most common use case is to create generators, that is, functions that return a new value from a given sequence each time they are called.
Fibonacci generator
Let's start with a simple example. We want to create a function that returns the next Fibonacci number each time it is called.
func fibonacci_generator() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b // update the variables in the surrounding scope
return a
}
}
To use this function, we need to call it first to get the generator function, and then call the generator function each time we want a new value:
package main
import "fmt"
func fibonacci_generator() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b // update the variables in the surrounding scope
return a
}
}
func main() {
fibgen := fibonacci_generator()
for i := 0; i < 10; i++ {
fmt.Println(fibgen())
}
}
Output
1
1
2
3
5
8
13
21
34
55
Prime number generator
Our next example is a bit more complex. We want to create a function that returns the next prime number each time it is called.
We will start by defining the next_prime
function, which returns the next prime that is greater than n
:
func is_prime(n int) bool {
for i := 2; i < n; i++ {
if n%i == 0 {
// n is divisible by i
return false
}
}
return true
}
func next_prime(n int) int {
n++ // we don't want to return n if it is prime
for !is_prime(n) {
n++
}
return n
}
This function is not very efficient, but it is good enough for our purpose. Now, we can define a generator that will output a new prime number each time it is called:
func prime_generator() func() int {
n := 2
return func() int {
n = next_prime(n) // update n in the surrounding scope
return n
}
}
And finally, a main
function that prints the first 10 prime numbers may look like this:
func main() {
// Print the first 10 prime numbers
gen := prime_generator()
for i := 0; i < 10; i++ {
fmt.Println(gen())
}
}
Let us stitch all the methods into a single program that prints the first 10 prime numbers.
package main
import "fmt"
func is_prime(n int) bool {
for i := 2; i < n; i++ {
if n%i == 0 {
// n is divisible by i
return false
}
}
return true
}
func next_prime(n int) int {
n++ // we don't want to return n if it is prime
for !is_prime(n) {
n++
}
return n
}
func prime_generator() func() int {
n := 2
return func() int {
n = next_prime(n) // update n in the surrounding scope
return n
}
}
func main() {
gen := prime_generator()
for i := 0; i < 10; i++ {
fmt.Println(gen())
}
}
Output
3
5
7
11
13
17
19
23
29
31
This is a rather advanced example, but it is closer to real-world use cases than the previous one.