Closure in Golang


January 15, 2022, Learn eTutorial
1158

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.

The idea of Variable scope & lifetime in Golang closure

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).

What is closure in Golang?

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

GO : Closure
  •   Obviously, there is an outer scope as F2 depicted in the diagram. There is a function F1 which is in the scope of some other function F2.
  •   Here F1 & F2 are nested functions. (a function inside another function)
  •   F1 refers to some variables that are local F2, which is going to be involved in closure.
  •   The function F1 closes over variable “b “ from function F2.

Let us understand with practical explanation for code given above:

  •   The code contains a function fib (fib( )). Fib does not return a value rather returns a function called func (func( ) ).
  •   fib( ) is F1 & func( ) is F2.
  •   The return type of fib( ) is a function func( ) that returns integer type,int.
  •   Therefore fib ( ) is a function returning another function.(outer function)
  •   The inner function is an 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.
  •   The variable a & b are declared in fib (F1). When the inner function is returned it will continue to refer to a & b even though the function fib is going away.
  •   When fib runs it returns a & b they will live on because the inner function returning closes over a & b so it keeps a & b alive.
     

Look at the below diagram

GO : Closure

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.  

NOTE:-f is closure on the right-hand side because it got a pointer to the anonymous function (fp) and a pointer to the environment(env) & on the left-hand side it is just a pointer to the function (fp)

 

Program for closure


// 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

What is the need for closure in Golang?

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.

How to create closure in Golang?

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   

GO : Closure

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

The unique environment of closure in Golang?

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