Go Closure
Jun 4, 2015 · 3 minute read · CommentsGoClosures
What are closures?
From Wikipedia
A closure is a data structure storing a function together with an environment, a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or storage location the name was bound to at the time the closure was created.
What does that mean?
In simple words, it means that a function can contain (or return) another function which is called closure. The unique property of this function (closure) is that, it has access to the variables which are accessible in the function that contains (or returned) this closure.
Not very clear?
function A has a local variable “a".
function A contains (or returns) another function, let’s call it B.
function B has access to the variable “a”.
If you have returned the function B, every time you call the function B, even though the function A is done executing, function B still can access and can manipulate the variable “a”.
The function B that we are referring to is a Closure.
Closures in Go
Go supports closures. Go also treats functions as first class citizens. We can assign functions to a variable, return functions from a function, pass functions to a function as parameters.
So, let’s see the famous tour.golang.org example of a closure in Go.
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
In the above example you could see that all though the variable “sum" is declared in the function adder, it is still used in the closures held by “pos" and “neg”.
Use case
The above example was one of the use case. Since I am new to closures, I always had a question while coding - “how do I realise if I have to use a closure in this case?”
Let’s consider a scenario where we need a struct that should be initialised with a number and it has a method that returns two values, one incremented and another decremented each time the method is called and that is the only functionality you need from this struct.
How would we do it?
Struct way
type IncDecStruct struct {
inc int
dec int
}
func getIncDecStruct(begin int) IncDecStruct {
incDecStruct := IncDecStruct{begin, begin}
return incDecStruct
}
func (i *IncDecStruct) IncDec() (int, int) {
i.dec = i.dec - 1
i.inc = i.inc + 1
return i.inc, i.dec
}
func main() {
a := getIncDecStruct(3)
fmt.Println(a.IncDec())
fmt.Println(a.IncDec())
fmt.Println(a.IncDec())
b := getIncDecStruct(10)
fmt.Println(b.IncDec())
fmt.Println(b.IncDec())
fmt.Println(b.IncDec())
}
You can run this code here to see the output.
Closure way
Let’s check if closures could help us ease this.
func IncDec(begin int) func() (int, int) {
inc := begin
dec := begin
return func() (int, int) {
inc = inc + 1
dec = dec - 1
return inc, dec
}
}
func main() {
closure1 := IncDec(3)
fmt.Println(closure1())
fmt.Println(closure1())
fmt.Println(closure1())
closure2 := IncDec(10)
fmt.Println(closure2())
fmt.Println(closure2())
fmt.Println(closure2())
}
The above code can be run here to see the output.
It’s easier this way, isn’t it? So, when you are creating a struct only because of its only method, then think about closures. You can store the contexts in a closure rather than a struct and its method.