Defer in Golang


January 15, 2022, Learn eTutorial
1508

In this tutorial, you will learn about defer statements in the Go programming language. From the previous tutorial, you learned control flow statements like if, switch, for loop, for –range loop that are most common in other programming languages. But defer in Golang is not common like other control flow statements.

What is defer in Golang?

The word defer means “put off (an action or event) to a later time or postpone “.In the Go programming language, a statement with defer keyword specifies that a particular statement needs to be postponed or execute sometime later but should be before exiting from the main loop.

  •   defer keyword used to specify a statement as defer.
  •   Usually used for clean-up functions in Go programs.
  •   Postpone execution of statement with defer keyword till the end of calling function
  •   Returns the value of the deferred statement just before the function exit.
  •   Here defer statement can be a function or an expression.

It is implemented as a stack data structure, all the functions are called on the stack in the last in first out manner except the defer keyword function call. It is called only after the last function call is returned.

How does defer work in Golang?

In a normal Go application or program, control flows from top to bottom of any function that we call. Generally, a function starts from the first line and executes through until it gets to the last line.
Let us just understand the same with a program. When we run the below code it just runs in sequential order and prints the output as “first”, “second”, “third”.


package main
import "fmt"
func main() {
    
    fmt.Println("First")
    fmt.Println("Second")
    fmt.Println("Third")
   
}

Output:


First
Second
Third

The defer keyword is used to differ the execution of statements. Suppose if defer keyword is placed in front of fmt.Println("Second")  you will notice that the second will be printed after the third.


package main
import "fmt"
func main() {
    
    fmt.Println("First")
    defer fmt.Println("Second")   //defer keyword
    fmt.Println("Third")
    
    
}

Output:


First
Second
Third

The defer keyword executes any functions that are passed into it after the function finishes its final statement but before it actually returns. So the way the main function ( ) is executed is it prints the first statement output in the above example “first”. Then in the next statement recognize a defer keyword in function call then print the last statement “third”. Then finally the main function ( ) exits & check if there are any deferred functions to call. Since there is one defer function, go ahead and call that function.

Note: Deferring does not move to the end of the main function actually moves it or works after the main function but before the main function returns.
  •   Defer keyword works in last in first out order or reverse order.
  •   When the compiler encounters a defer statement in a function it pushes it onto a stack data structure.  
  •   All the encountered defer statements are pushed onto the stack. 
  •   When the surrounding function returns than all the functions in the stack starting from top to bottom are executed before execution can begin in the calling function. The same thing happens while the calling function as well
     

Resource clean up using Defer statements

The key advantage of deferring keywords in the Go programming language is for resource clean-up like open files, to handle database, network connections, etc. Once after the termination of a program in execution using certain resources for successful completion of a program, there is a need to close each resource used to avoid resource conflict when some other programs are waiting for the same resources.

Defer statement makes the Go code error-free by closing all the files or resources that are opened during program execution.

In Go defer resource clean-up is often. Let us understand with an example how to defer a statement while writing to a file. Once after opening a file it needs to close.
 

Program of writing to a file


package main
import (
    "fmt"
    "log"
    "os"
)

func main() {
    err := writeToFile("Some text")
    if err != nil {
        log.Fatalf(err.Error())
    }
    fmt.Printf("Write to file succesful")
}

func writeToFile(text string) error {
    file, err := os.Open("temp.txt")
    if err != nil {
        return err
    }
    n, err := file.WriteString("Some text")
    if err != nil {
        return err
    }
    fmt.Printf("Number of bytes written: %d", n)
    file.Close()
    return nil
}

The above-given Go code opens a file. The function writeToFile opens a file & writes some information/contents to the file. After finishing writing to a file the next step is to close the file. There is a chance of the occurrence of an error during a write operation. In such a case, it will return an error and exit the function. The function tries to close the file and resources used are released back to the system. Finally returns a nil value after successful completion of writing to a file. 

The function call to file.WriteString fails, the function will return without closing the file and releases the resource back to the system. This problem can be fixed using defer keyword instead of using a file.Close() statement. The defer keyword executes before the function returns to avoid or fix such problems.

After  rewriting the above code looks like


package main

import (
    "fmt"
    "log"
    "os"
)

func main() {
    err := writeToFile("Some text")
    if err != nil {
        log.Fatalf(err.Error())
    }
    fmt.Printf("Write to file succesful")
}

func writeToFile(text string) error {
    file, err := os.Open("temp.txt")
    if err != nil {
        return err
    }
    defer file.Close()    //defer statement

    n, err := file.WriteString("Some text")
    if err != nil {
        return err
    }
    fmt.Printf("Number of bytes written: %d", n)
    return nil
}

The defer file.Close () closes the file after a file is opened. This defers the file.close() ensures closing of a file is carried out through the write to same file results in some error.

Multiple defer keywords in Golang

A Golang can have multiple defer keywords used inside a program. Let us check it with the below given example where three defer statements are executed. The concept of the stack works here.

  •   The first defer statement prints first. (top-2 )
  •   The second defer statement prints second (top-1)
  •   The third defer statement prints the third(top)
     

These are pushed onto a stack. The top position holds the last print statement i.e., third.

GO : Defer

Observe the output for the below code it is printed reverse order just as it is pushed onto the stack. The deferred statements occupy in reverse order one above the previous one which results in Last In, First Out manner.

Program with multiple defer keywords


package main
import "fmt"

func main() {
    defer fmt.Println("First")
    defer fmt.Println("Second")
    defer fmt.Println("Third")
}

Output:


First
Second
Third

How to evaluate a defer argument?

Defer arguments are evaluated during the time when defer statements are evaluated.
Let us understand with a simple program 
 


package main
import "fmt"

func main() {
 statement := "Go language in Learn  eTurorials"

 defer fmt.Printf("In defer statement  is: %s\n", statement)
 statement = "Learn  eTurorials"

  }

Output:


In defer statement is: Go language in Learn  eTurorials

In the given program a variable statement of string data type is considered as of defer statement. The defer statement is evaluated with a value Go language in Learn eTutorials assigned to the variable statement. The defer statement prints the value of the variable statement. Later in the next line changes the value of the statement variable with “Learn eTutorials”. You can see the output of the above code evaluate defer statement variable only, though the value assigned to the same variable is undergone a change.