Understanding Go's defer
Statement: A Complete Guide
Have you ever written a Go code? Of course you have - that's why this post is recommended to you! And if your answer is yes, then you might have come across the keyword defer
. So let's understand this in detail so that we can write better Go code (after all, as gophers our aim is to write code that works and not fall for anything like other language folks do, haha just kidding).
But What is defer
?
So if you look for the official definition it goes like: "defer
schedules a function call to run right after the surrounding function returns". Ok but what does this actually mean? In simple terms, this means that any function call preceded by defer
is added to a stack of deferred calls and will be executed just before the parent function (where the defer is declared) exits.
The deferred calls are executed in Last-In, First-Out (LIFO) order.
So How Does defer
Work?
Let's take a code example which will help us understand this better and clear up what is the LIFO execution that we talked about earlier. So below is a simple Go code with some addition and some print statements. I think this is a pretty simple yet effective example to understand defer without buzzwords.
package main
import "fmt"
func main() {
a := 54
b := 34
c := a + b
fmt.Println(c) // Prints the sum immediately
defer fmt.Printf("from defer: %v\n", a + b)
defer fmt.Println("hello world from defer")
fmt.Printf("Hello, World!\n")
}
Any guesses what will be the output? Let's look at the output first:
88
Hello, World!
hello world from defer
from defer: 88
Why and How This Happens
Let's analyze the execution flow of Go's defer
statement step by step.
Step-by-Step Execution
Immediate Execution:
- Computes
c = a + b
→88
- Prints:
88
Deferring Function Calls:
defer fmt.Printf("from defer: %v\n", a + b)
defer fmt.Println("hello world from defer")
Arguments are evaluated immediately:
-
a + b
→88
-
"hello world from defer"
is ready - Functions themselves are pushed onto a stack for later execution
Regular Execution Continues:
- Prints:
Hello, World!
Deferred Functions Execute in Reverse (LIFO):
- First, prints the last deferred call:
hello world from defer
- Then, prints the first deferred call:
from defer: 88
Complete Output
88
Hello, World!
hello world from defer
from defer: 88
Key Takeaways
- Arguments to deferred functions are evaluated when
defer
is encountered - Deferred functions execute in Last-In-First-Out (LIFO) order
- Deferred functions run just before the surrounding function returns
More Common Use Cases: File Handling
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("example.txt")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
// Ensure the file gets closed when the function exits
defer file.Close()
fmt.Println("File opened successfully.")
}
👉 Here, file.Close()
is guaranteed to run at the end of main()
, even if the function returns early due to an error. This helps a lot in resource cleanup and making sure the file is closed after usage.
Ok, So We've Understood defer, Now Let's Do Something Fun
One interesting trick with defer
is reversing a string without using loops or extra arrays. Since deferred functions execute in Last-In, First-Out (LIFO) order, we can take advantage of this to print characters in reverse.
package main
import "fmt"
func main() {
word := "golang"
fmt.Print("Reversed word: ")
for i := 0; i < len(word); i++ {
ch := word[i] // capture the character immediately
defer fmt.Printf("%c", ch)
}
}
How It Works
- Each iteration of the loop defers printing a character
- Deferred calls are stacked, so they execute in reverse order when
main()
ends - The result is the string printed backwards:
Reversed word: gnalog
Conclusion
I hope this post has helped you understand defer
in an easy and fun way!
Happy coding in Go! 🐹
Top comments (1)
Feel free to add something, you feel is missing here.