What the heck is defer?

Do you struggle to get the hang of defer too?
Worry not 😄, I will try to explain it as simply as I can in this post.

What is defer?

A defer statement defers the execution of a function until the surrounding function returns.

The deferred call’s arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.

This program explains the execution of defer in a bit easier way:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func a() {
    defer un(trace("a"))    // similarly trace("a") also gets
                            // executed immediately
    fmt.Println("in a")
}

func b() {
    defer un(trace("b"))    // trace("b") gets executed
                            // immediately but un("b") gets
                            // execute at the very last
    fmt.Println("in b")
    a()
}

func main() {
    b()
}

Output:

1
2
3
4
5
6
7
8
entering: b     // output of trace("b")
in b            // note that un("b") is not executed instead
                // program moves ahead
entering: a     // output of trace("a")
in a
leaving: a      // finally defered un("a") is called as a()
                // returns
leaving: b      // at last un("b") is called
Tip
Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.

Here is a small program which visualises this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package main

import "fmt"

func main() {
    fmt.Println("counting \n")
    defer fmt.Println("\ndone")     // This will get executed at
                                    // the very last

    for i := 0; i < 10; i++ {
        defer fmt.Println(i)
    }
}

Output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
counting

9
8
7
6
5
4
3
2
1

done

However remember deferred function’s arguments are evaluated immediately, hence it can give a different result

1
2
3
4
5
i := 0
defer fmt.Println(i)
i++

// It will print 0 even though i has become 1

A particularly good use of defer is to close a file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main
import (
    "os"
)

func main() {
    f, _ := os.Create("test.txt")
    defer f.Close()
    /*
        Stuff
    */
}
Abstract
Deferring a call to a function such as Close has two advantages. First, it guarantees that you will never forget to close the file, a mistake that’s easy to make if you later edit the function to add a new return path. Second, it means that the close sits near the open, which is much clearer than placing it at the end of the function. Source
Tip
Read an in-depth article on defer to understand it better: Defer, Panic, and Recover