Go Defer Statement: What It Is And When To Use

The Go defer statement allows you to schedule a function to be called immediately before the surrounding function returns.

If you are familiar with Python, you probably know about Python’s with statement. The goal of this construct is never to forget freeing or closing resources. The Go defer statement was added to Go for precisely the same reason. In this article, I’ll explain what defer is, why it’s useful, and when and how to use it.

What is Go’s defer statement?

The defer statement in Go allows you to schedule a function to be called immediately before the surrounding function returns. It is often used to perform cleanup tasks, such as closing a file, a database connection, or unlocking a mutex.

The defer statement:

  • helps us keep related code close together, e.g., the opening and closing of a file.
  • Helps in not forgetting to free up resources (like open files)

Let’s look at an example:

file, err := os.Open("myfile.txt")
if err != nil {
    // handle the error
}
defer file.Close()

// read and process the fileCode language: Go (go)

When we open a file and that action was successful (no error), we directly tell Go to close the file as soon as this function ends using a deferred close call. The defer statement doesn’t add much value as long as our code follows the happy flow (everything is going as planned). We could just as well put the file closing operation at the end of the function, a pretty logical spot to close resources.

But what if everything doesn’t go as planned? What if an error occurs right in the middle of our function? We want to return an error, but we also have to think about closing the file. Chances are we will forget, creating a resource leak. This is why defer makes life a lot easier for Go programmers. We already told Go to close the file whenever we exit the function, even when we exit with an error!

Last in, first out

When a function returns, its deferred calls are executed in last-in-first-out order, often abbreviated as LIFO. The following example demonstrates this:

func foo() {
    defer fmt.Println("defer 1")
    defer fmt.Println("defer 2")
    defer fmt.Println("defer 3")
    fmt.Println("foo")
}

foo()
// Output:
// foo
// defer 3
// defer 2
// defer 1Code language: Go (go)

Good to know about Go Defer statements

Some important things to keep in mind:

  • defer statements can take a function call as an argument. The arguments to the function are evaluated when the defer statement is encountered, but the function itself is not called until the surrounding function returns.
  • defer statements are executed even if a return or panic statement is encountered in the function. This makes it helpful in performing cleanup tasks even in the event of an error or abnormal termination.

Learn more about Go’s Defer