I\'m reading \'CreateSpace An Introduction to Programming in Go 2012\'
and on page 86 I found this evil magic
func makeEvenGenerator() func() uint {
For the sake of clarity, I'll assign names to both functions:
func makeEvenGenerator() func() uint { // call this "the factory"
i := uint(0)
return func() (ret uint) { // call this "the closure"
ret = i
i += 2
return
}
}
The factory returns the closure – functions are first class citizens in Go i.e. they can be right-hand expressions, for example:
f := func() { fmt.Println("f was called"); }
f() // prints "f was called"
In your code, the closure wraps over the context of the factory, this is called lexical scoping. This is why the variable i
is available inside the closure, not as a copy but as a reference to i
itself.
The closure uses a named return value called ret
. What this means is that inside the closure you'll have implicitly declared ret
and at the point of return
, whatever value ret
has will be returned.
This line:
ret = i
will assign the current value of i
to ref
. It will not change i
. However, this line:
i += 2
will change the value of i
for the next time the closure is called.
Here you'll find a little closure example I wrote together for you. It's not extremely useful but illustrates the scope, purpose and use of closures pretty well in my opinion:
package main
import "fmt"
func makeIterator(s []string) func() func() string {
i := 0
return func() func() string {
if i == len(s) {
return nil
}
j := i
i++
return func() string {
return s[j]
}
}
}
func main() {
i := makeIterator([]string{"hello", "world", "this", "is", "dog"})
for c := i(); c != nil; c = i() {
fmt.Println(c())
}
}