In this tutorial, you will learn how to work with closures in Golang. Before discussing closure we need to understand the concept of variable scope & lifetime. You will cover the need for closure and its unique environment.
Consider a function with a variable declared inside that function which is visible inside that function. The scope is static which is a feature of programming code that we write & is based on compile-time whereas lifetime depends on program execution (runtime).
A closure is a function inside another function “closes over” one or more local variables of the outer function. Golang supports nested functions
. A nested function is a function that is defined inside another function.
Consider the below example code
func fib() func() int {
a, b := 0,1
return func() int {
a, b = b, a+b
return b
}
}
A closure involves a function that uses variables from another function scope
Let us understand with practical explanation for code given above:
anonymous function
it does not have a name.It is just a function literal with some code.it uses variables a & b it did not declare a & b.Look at the below diagram
The figure shows function on the left hand and closure on the right-hand side. Suppose there is a variable assignment
f:= fib
f is declared and assigned the value of fib, here the fib is used without any parenthesis only the name fib is taken that refers to the function not as a function calf here act as a pointer that points to the code i.e. it will point to the function fib
if f is called as a function with parentheses i.e. like fib( ) function call.f & fib are two names for the same thing. These are represented by the left-hand side of the above picture.
Next on the right-hand side, call the function fib( ) and assign to variable f.
f := fib( )
f is not a function it is a closure. There are two parts env & fp.In the above-discussed code, there is an anonymous function (F2) that is actually returned from fib in the first part. The second part holds information about where to find a & b. Because the anonymous inner function changes the values of a & b and it returns b.
So a closure is a runtime invisible practice on the background of a program.
// Anonymous functions are useful when you want to define
// a function inline without having to name it.
package main
import "fmt"
// This function `fib` returns another function, which
// we define anonymously in the body of `fib`. The
// returned function _closes over_ the variable `a & b` to
// form a closure.
func fib() func() int {
a, b := 0,1
return func() int {
a, b = b, a+b
return b
}
}
func main() {
f := fib()
for x:=f();x<100;x=f() {
fmt.Println(x); // 1 2,3,4,8,13,21,34,55,89
}
}
Output:
1 2 3 5 8 13 21 34 55 89
The need for closure in Golang i.e., a function returning another function is scoping. Suppose there is a function with some values initialized to a variable within it. A function is just a set of instructions to be executed. The inner function within that function will use the value initialized by the outer function.
The creation of closure is done by declaring an anonymous function inside an outer function that is already declared. That function can access its surrounding states and form unique.
Example
The below code is a closure of function f containing i. The closure property is satisfied, the anonymous function f can access the value of i directly.
package main
import (
"fmt"
)
func main() {
i := 40
f := func() {
// has access to i
j := i - 2
fmt.Println(j)
}
f() // 38
}
Output:
38
Golang supports the data isolation property that is available in the closure function. Whenever a closure is created its state remains unique. This makes each one of them have its own state. The inner variables are unique to each closure.
Let us understand with an example
package main
import "fmt"
func fib() func() int {
a, b := 0, 1
// return a closure over a & b
return func() int {
a, b = b, a+b
return b
}
}
func main(){
f , g := fib(), fib()
// f & g have their own copies of a & b
fmt.Println(f(),f(),f())
fmt.Println(g(),g(),g()) //f() , g() prints identical lines 1,2,3
}
Output:
1 2 3 1 2 3