Golang Tutorial
Fundamentals
Control Statements
Functions & Methods
Structure
Arrays & Slices
String
Pointers
Interfaces
Concurrency
The defer
statement in Go is a powerful feature used to ensure that a function call is performed later in a program's execution, usually for cleanup purposes. It's typically used with resource release operations like closing files, disconnecting network connections, or unlocking resources.
Let's explore the defer
statement in detail.
The basic idea is that defer
postpones the execution of a function until the surrounding function returns.
package main import "fmt" func main() { defer fmt.Println("World") fmt.Println("Hello") }
Output:
Hello World
The above program will print "Hello" first, and then "World" because the call to fmt.Println("World")
is deferred.
If multiple defer
statements are used, they will be executed in a LIFO (Last-In, First-Out) order:
package main import "fmt" func main() { defer fmt.Println("First defer") defer fmt.Println("Second defer") fmt.Println("Regular statement") }
Output:
Regular statement Second defer First defer
A common use case for defer
is to release resources, like closing files:
package main import ( "fmt" "os" ) func main() { file, err := os.Create("sample.txt") if err != nil { panic(err) } defer file.Close() file.WriteString("This is a sample text.") }
Here, the file.Close()
method will be called after all other operations in the main
function are completed, ensuring that the file is properly closed before the program exits.
Be cautious when using defer
inside loops, as it can cause resource exhaustion since the deferred calls won't execute until the surrounding function exits.
For example, if you're opening files in a loop and deferring their closures, you might run into a situation where you've opened too many files and can't open any more until the surrounding function exits and the deferred closures execute.
The arguments of a deferred function are evaluated when the defer
statement is executed, not when the deferred function is called:
package main import "fmt" func main() { i := 1 defer fmt.Println(i) // This will print "1" i++ fmt.Println("Done") }
Output:
Done 1
Even though the value of i
was changed after the defer
statement, the deferred function prints the value of i
at the time the defer
statement was executed.
The defer
statement in Go is a handy tool for ensuring certain operations are performed after the main logic of a function. Whether you're cleaning up resources or ensuring certain post-conditions, defer
can help make your code cleaner and more maintainable.
How to Use Defer in Golang:
defer
is used to ensure that a function call is performed later in a program's execution, usually for cleanup operations.package main import "fmt" func main() { defer fmt.Println("World") fmt.Println("Hello") }
Deferred Function Calls in Golang:
package main import "fmt" func main() { defer fmt.Println("Second") fmt.Println("First") }
Order of Execution with Defer in Golang:
package main import "fmt" func main() { defer fmt.Println("First") defer fmt.Println("Second") fmt.Println("Last") }
Common Use Cases for Defer in Golang:
defer
.package main import ( "fmt" "os" ) func main() { file, err := os.Open("example.txt") if err != nil { fmt.Println("Error opening file:", err) return } defer file.Close() // File processing code... }
Error Handling with Defer in Golang:
package main import ( "fmt" "os" ) func main() { file, err := os.Open("example.txt") if err != nil { fmt.Println("Error opening file:", err) return } defer func() { if err := file.Close(); err != nil { fmt.Println("Error closing file:", err) } }() // File processing code... }
Panics and Recover with Defer in Golang:
panic
triggers a runtime error, and recover
is used to capture and handle panics, often in deferred functions.package main import "fmt" func main() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered from panic:", r) } }() // Trigger a panic panic("Panic occurred!") }
Benefits of Using Defer in Golang:
defer
simplifies cleanup and resource management, making code more readable.package main import "fmt" func main() { defer cleanup() // Code... } func cleanup() { // Cleanup operations... fmt.Println("Cleanup completed.") }
Defer vs Immediate Execution in Golang:
package main import "fmt" func main() { defer fmt.Println("Deferred execution") fmt.Println("Immediate execution") }
Practical Examples of Defer in Golang:
defer
.package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() fmt.Println("Goroutine completed.") }() wg.Wait() fmt.Println("Main function completed.") }