Go: how the defer keyword works

Go, also known as Golang, is an open source programming language developed by Google. It is appreciated for its efficiency, simplicity and native concurrency. One of Go's coolest features is the "defer" keyword, which is used to manage resources and improve code cleanliness. In this article, we will explore in detail the use of "defer" in Go and how it can simplify resource management and improve code maintainability.

The "defer" keyword in Go is used to postpone the execution of a function until the containing function has completed. In other words, it allows you to schedule a function to run at a later time, usually at the end of the current block of code or when a function is about to return a value. This is especially useful for performing resource "cleanup" or "release" operations such as closing files, network connections, channels, or mutexes.

The syntax of "defer" is simple:


func main() {
     // Previous code
    
     defer myFunc()
    
     // Next code
}

When the program executes the "defer" block, Go registers the specified function and will execute it when the block completes or when the function containing the "defer" is about to return a value.

One of the main uses of "defer" in Go is for resource management. For example, when opening files or network connections, it is crucial to ensure that these resources are closed properly once they are no longer needed, to avoid memory leaks or locked resources. "Defer" greatly simplifies this operation.

Here is an example of how to use "defer" to close a file securely:


func readFile(fileName string) (string, error) {
     file, err := os.Open(fileName)
     if err != nil {
         return "", err
     }
    
     defer file.Close() // Close the file at the end of the function
    
     // Read the contents of the file
    
     return contents, nil
}

In this example, "file.Close()" will be automatically called when the "readFile" function exits, ensuring that the file is closed correctly, regardless of how the function exits (normally or due to an error).

You can also use "defer" to defer multiple functions in the same block. These functions will be executed in reverse order, with the last "defer" function executed first. This can be useful when multiple cleanup actions are needed:


func test() {
     defer step3()
     defer step2()
     defer step1()
    
     // Code here
}

In this case, step1 will be executed first, followed by step2 and finally step3 when the test function ends.

"Defer" can also be used together with the panic and recover mechanisms in Go to handle exceptional situations. When a panic occurs, it clears the call stack, executing any "defer" functions along the way, and ultimately terminates the program unless recovered. Here's an example:


func main() {
     defer func() {
         if r := recover(); r != nil {
             fmt.Println("Restored by panic:", r)
         }
     }()
    
     // Some code that might cause a panic
}

In this example, the "defer" function will capture any panics that occur in the code within the "main" function, allowing the program to recover in a controlled manner and potentially log the panic.

Conclusions

In conclusion, the "defer" keyword in Go is a powerful and useful feature that makes resource management and code cleanup much easier. By allowing functions to be scheduled to run at a later time, it helps ensure resources are freed properly and makes code cleaner and more maintainable. It is one of the defining features of Go that makes it an effective programming language for writing robust and efficient software.

Back to top