Is golang defer statement execute before or after return statement?

Thanks @dev.bmax @Tranvu Xuannhat @rb16. With your help, I found the key explanation from Defer_statements.

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

We can break up defer ... into three parts.

  1. invoke defer, evaluating the value of function parameter.
  2. execute defer, pushing a function in to stack.
  3. execute functions in stack after return or panic.

I made a new test4 to explain.

func test4() (x int) {
    defer func(n int) {
        fmt.Printf("in defer x as parameter: x = %d\n", n)
        fmt.Printf("in defer x after return: x = %d\n", x)
    }(x)

    x = 7
    return 9
}

In test4,

  1. invoke defer, evaluating the value of n, n = x = 0, so x as parameter is 0.
  2. execute defer, pushing func(n int)(0) onto stack.
  3. execute func(n int)(0) after return 9, n in fmt.Printf("in defer x as parameter: x = %d\n", n) has been evaluated, x in fmt.Printf("in defer x after return: x = %d\n", x) will be evaluated now, x is 9。

So, got the result:

test4
in defer x as parameter: x = 0
in defer x after return: x = 9
in main: x = 9

In the first test, the value of the parameter x is evaluated when the line containing the defer runs. And it happens in line 1 when x is still 0.

Note, that even though fmt.Printf will be called later, it's parameters are evaluated ahead of time.

In the third test, the value of the parameter x is set to 7 before the defer statement runs. Again, this happens before the actual invocation of fmt.Printf.

The second test is a little different. Variable x is within the scope of the anonymous function. It's value is evaluated when the function runs, which happens when the test function returns. By that time x is 9.


I will refer to Defer_statements to explain your results.

Question 2: Defer executes after return.

Question 1: From the docs

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

  • Test 1: Defer invokes fmt.Println. fmt.Println evaluates the value of x, which is 0 (zero value). test1() return 9 in the main function.

  • Test 2: Defer invokes func() {}. fmt.Println only evaluates x when func() {} is executed (after return). Hence, x is evaluated to 9. test2() return 9 in the main function.

  • Test 3: Defer invokes fmt.Println. fmt.Println evaluates the value of x, which is 7 (x is assigned to 7). test3() return 9 in the main function.

Tags:

Go