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.
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:
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:
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
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 visualise this:
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:
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
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.
package main
import (
"os"
)
func main() {
f, _ := os.Create("test.txt")
defer f.Close()
/*
Stuff
*/
}
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
Hope you learned something new 😁.
Top comments (0)