— Go, Defer Statement — 1 min read
In Go programming, the defer
statement is a powerful construct that allows you to schedule a function call to be executed just before the surrounding function returns. It provides an elegant way to manage resources and perform cleanup operations. This article will explore the fundamentals of the defer
statement and demonstrate its usefulness through various examples.
The defer
statement is straightforward to use. Simply prefix a function call with the defer
keyword, and it will be deferred until the surrounding function completes. Let's consider a simple example to illustrate its usage:
1func main() {2 defer fmt.Println("World")3
4 fmt.Println("Hello")5}
When executing this code, the output will be:
1Hello2World
As you can see, even though we invoked fmt.Println("World")
first, it was deferred until after the completion of the main
function, resulting in "World" being printed last.
One common use case for the defer
statement is to ensure proper cleanup of resources, such as closing files or releasing locks, regardless of the control flow or potential errors. Consider the following example:
1func processFile(filename string) error {2 file, err := os.Open(filename)3 if err != nil {4 return err5 }6 defer file.Close()7
8 // Process the file here...9
10 return nil11}
In this example, the defer
statement ensures that the file is closed before the processFile
function exits, regardless of any errors encountered during processing.
It's worth noting that the arguments in a deferred function call are evaluated immediately, not at the time of execution. Let's see an example to understand this behavior:
1func printNumber(n int) {2 fmt.Println(n)3}4
5func main() {6 for i := 0; i < 5; i++ {7 defer printNumber(i)8 }9}
The output of this code will be:
1423324150
Here, each iteration of the loop defers the execution of printNumber(i)
. Since the argument i
is evaluated at the time of the defer statement, the value printed reflects the current value of i
.
When multiple defer
statements are present in a function, they are executed in reverse order, similar to a stack. Consider the following example:
1func main() {2 defer fmt.Println("First")3 defer fmt.Println("Second")4 defer fmt.Println("Third")5}
In this case, the output will be:
1Third2Second3First
As you can see, the most recently deferred function call is executed first, followed by the next one, until all deferred calls have been executed.
When a panic occurs in Go, the deferred functions still get executed before the program terminates. This behavior allows you to perform cleanup operations even in exceptional scenarios. Here's an example:
1func cleanup() {2 fmt.Println("Performing cleanup...")3}4
5func process() {6 defer cleanup()7
8 // Perform some work...9
10 if err := recover(); err != nil {11 fmt.Println("Panic occurred:", err)12 }13}14
15func main() {16 process()17}
In this code, the cleanup
function is deferred within the process
function. If a panic occurs during the execution of process
, the cleanup
function will still be called, allowing you to release any acquired resources or perform necessary cleanup tasks.