Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang defer behavior

Tags:

go

People also ask

How does defer work in Golang?

In Golang, the defer keyword is used to delay the execution of a function or a statement until the nearby function returns. In simple words, defer will move the execution of the statement to the very end inside a function.

Does panic call defer?

defer won't work after panic because the control never reached the statement, hence it was never registered. This is like printing something after a return statement in a function, it's basically an unreachable code.

Does defer run on panic Golang?

In Go, we use defer, panic and recover statements to handle errors. We use defer to delay the execution of functions that might cause an error. The panic statement terminates the program immediately and recover is used to recover the message during panic.

Does defer happen after return?

defer statement is a convenient way to execute a piece of code before a function returns, as explained in Golang specification: Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred.


That seems coherent (see also "Defer, Panic, and Recover")

Deferred function calls are executed in Last In First Out order after the surrounding function returns.

This function prints "3210":

func b() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }
}

The last call when the defer is evaluated means i=3, the previous to last means i=2 and so on.

Golang spec:

Each time the "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function body is not executed.


the defers will be called when func ends

yes, but their arguments are evaluated before, while the loop is running.

You have a trickier defer case in "How golang's “defer” capture closure's parameter?" when used with closure (function literal), as detailed in "Why add “()” after closure body in Golang?".


A little further down, the spec also explicitly says that parameters are evaluated at the time the defer statement runs, not at return/panic time when the deferred function is actually called:

Each time the "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function body is not executed.

And yes, it can definitely be confusing that the parameters are evaluated at one time and the function body runs at another. I've been caught by it.


I think your confusion is about what the phrases "the defer executes" and "the call executes" mean. I believe, "the defer executes" is when the flow of control reaches the line starting with defer, i.e. this happens five times inside the loop. In contrast, "the call executes" is when the fmt.Printf("%d ", i) is executed, i.e. when the surrounding function returns.

If this interpretation is correct, the your statement "since the defers will be called when the for loop ends" is wrong (printf will be called after the loop, but defer is called inside), and everything is consistent with the behaviour explained in the other answers.