Welcome to tutorial no. 29 in Golang tutorial series.

What is Defer?

Defer statement is used to execute a function call just before the surrounding function where the defer statement is present returns. The definition might seem complex but it's pretty simple to understand by means of an example.

Example

package main

import (  
    "fmt"
)

func finished() {  
    fmt.Println("Finished finding largest")
}

func largest(nums []int) {  
    defer finished()    
    fmt.Println("Started finding largest")
    max := nums[0]
    for _, v := range nums {
        if v > max {
            max = v
        }
    }
    fmt.Println("Largest number in", nums, "is", max)
}

func main() {  
    nums := []int{78, 109, 2, 563, 300}
    largest(nums)
}
largestdefer finished()finished()largest
Started finding largest  
Largest number in [78 109 2 563 300] is 563  
Finished finding largest  
finishedFinished finding largest

Deferred methods

Defer is not restricted only to functions. It is perfectly legal to defer a method call too. Let's write a small program to test this.

package main

import (  
    "fmt"
)


type person struct {  
    firstName string
    lastName string
}

func (p person) fullName() {  
    fmt.Printf("%s %s",p.firstName,p.lastName)
}

func main() {  
    p := person {
        firstName: "John",
        lastName: "Smith",
    }
    defer p.fullName()
    fmt.Printf("Welcome ")  
}

In the above program we have deferred a method call in line no. 22. The rest of the program is self explanatory. This program outputs,

Welcome John Smith  

Arguments evaluation

defer

Let's understand this by means of an example.

package main

import (  
    "fmt"
)

func printA(a int) {  
    fmt.Println("value of a in deferred function", a)
}
func main() {  
    a := 5
    defer printA(a)
    a = 10
    fmt.Println("value of a before deferred function call", a)

}
a5aprintAaa
value of a before deferred function call 10  
value of a in deferred function 5  
a10printA(a)5

Stack of defers

When a function has multiple defer calls, they are pushed on to a stack and executed in Last In First Out (LIFO) order.

We will write a small program which prints a string in reverse using a stack of defers.

package main

import (  
    "fmt"
)

func main() {  
    name := "Naveen"
    fmt.Printf("Original String: %s\n", string(name))
    fmt.Printf("Reversed String: ")
    for _, v := range name {
        defer fmt.Printf("%c", v)
    }
}
for rangedefer fmt.Printf("%c", v)
defer fmt.Printf("%c", 'n')

This program will output,

Original String: Naveen  
Reversed String: neevaN  

Practical use of defer

The code samples we saw so far don't show the practical use of defer. In this section we will look into some practical uses of defer.

Defer is used in places where a function call should be executed irrespective of the code flow. Let's understand this with the example of a program which makes use of WaitGroup. We will first write the program without using defer and then we will modify it to use defer and understand how useful defer is.

package main

import (  
    "fmt"
    "sync"
)

type rect struct {  
    length int
    width  int
}

func (r rect) area(wg *sync.WaitGroup) {  
    if r.length < 0 {
        fmt.Printf("rect %v's length should be greater than zero\n", r)
        wg.Done()
        return
    }
    if r.width < 0 {
        fmt.Printf("rect %v's width should be greater than zero\n", r)
        wg.Done()
        return
    }
    area := r.length * r.width
    fmt.Printf("rect %v's area %d\n", r, area)
    wg.Done()
}

func main() {  
    var wg sync.WaitGroup
    r1 := rect{-67, 89}
    r2 := rect{5, -67}
    r3 := rect{8, 9}
    rects := []rect{r1, r2, r3}
    for _, v := range rects {
        wg.Add(1)
        go v.area(&wg)
    }
    wg.Wait()
    fmt.Println("All go routines finished executing")
}
rectarearect
mainr1r2r3rectrectsfor rangeareawgwg.Done()defer

Let's rewrite the above program using defer.

wg.Done()defer wg.Done()
package main

import (  
    "fmt"
    "sync"
)

type rect struct {  
    length int
    width  int
}

func (r rect) area(wg *sync.WaitGroup) {  
    defer wg.Done()
    if r.length < 0 {
        fmt.Printf("rect %v's length should be greater than zero\n", r)
        return
    }
    if r.width < 0 {
        fmt.Printf("rect %v's width should be greater than zero\n", r)
        return
    }
    area := r.length * r.width
    fmt.Printf("rect %v's area %d\n", r, area)
}

func main() {  
    var wg sync.WaitGroup
    r1 := rect{-67, 89}
    r2 := rect{5, -67}
    r3 := rect{8, 9}
    rects := []rect{r1, r2, r3}
    for _, v := range rects {
        wg.Add(1)
        go v.area(&wg)
    }
    wg.Wait()
    fmt.Println("All go routines finished executing")
}

This program outputs,

rect {8 9}'s area 72  
rect {-67 89}'s length should be greater than zero  
rect {5 -67}'s width should be greater than zero  
All go routines finished executing  
areaifwg.Done()wg.Done()wg.Done()

This brings us to the end of this tutorial. Have a good day.

Next tutorial - Error Handling