golang defer语句是在return语句之前还是之后执行?

golang defer语句是在return语句之前还是之后执行?

问题描述:

I have a question about golang defer: Is golang defer statement execute before or after return statement?

I have read Defer_statements. But I do not got the answer.

I made a simple test:

func test1() (x int) {
    defer fmt.Printf("in defer: x = %d
", x)

    x = 7
    return 9
}

func test2() (x int) {
    defer func() {
        fmt.Printf("in defer: x = %d
", x)
    }()

    x = 7
    return 9
}

func test3() (x int) {
    x = 7
    defer fmt.Printf("in defer: x = %d
", x)
    return 9
}

func main() {
    fmt.Println("test1")
    fmt.Printf("in main: x = %d
", test1())
    fmt.Println("test2")
    fmt.Printf("in main: x = %d
", test2())
    fmt.Println("test3")
    fmt.Printf("in main: x = %d
", test3())
}

In test1(), using Printfto print x after defer. In test2(), using a anonymous function to print x after defer. In test3(), using Printfto print x after defer, but defer after x = 7.

But the result is:

test1
in defer: x = 0
in main: x = 9
test2
in defer: x = 9
in main: x = 9
test3
in defer: x = 7
in main: x = 9

So, is any one can explain: 1. why got this result? why test1 prints 0, test2 print9, test3 prints 7. 2. is defer statement excutes after return or before return?

Thanks a lot.

我对golang延迟有疑问: golang延迟语句是在return语句之前还是之后执行? strong> p>

我已阅读 Defer_statements 。 但是我没有答案。 p>

我做了一个简单的测试: p>

  func test1()(x int){
 延迟fmt.Printf(“延迟:x =%d 
”,x)
 
x = 7 
返回9 
} 
 
func test2()(x int){
延迟func()  {
 fmt.Printf(“延迟:x =%d 
”,x)
}()
 
x = 7 
返回9 
} 
 
func test3()(x int)  {
x = 7 
延迟fmt.Printf(“延迟:x =%d 
”,x)
返回9 
} 
 
func main(){
 fmt.Println(“ test1”  )
 fmt.Printf(“ in main:x =%d 
”,test1())
 fmt.Println(“ test2”)
 fmt.Printf(“ in main:x =%d 
”  ,test2())
 fmt.Println(“ test3”)
 fmt.Printf(“ in main:x =%d 
”,test3())
} 
  code>  pre>  
 
 

test1() code>中,使用 Printf code>在延迟后打印x。 在 test2() code>中,使用匿名 函数在延迟后打印x。 在 test3() code>中,使用 Printf code>在延迟后打印x,但在 x = 7 code>之后延迟。 / p>

但是结果是: p>

  test1 
推迟:x = 0 
 在主程序中:x = 9 
test2 
延迟:x = 9 
主程序:x = 9 
test3 
in延迟:x = 7 
在主程序中:x = 9 
  code>  pre> 
  
 

因此,有谁能解释: 1。 为什么得到这个结果? 为什么test1打印0,test2打印9,test3打印7。 2。 返回语句是在返回之后还是返回之前执行? p>

非常感谢。 p> div>

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)
        fmt.Printf("in defer x after return: x = %d
", 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) has been evaluated, x in fmt.Printf("in defer x after return: x = %d ", 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.

It's not before or after, it's all about if the defer statement is present in the stack or not. if it is (if the control reaches to the defer statement it saves stores statement into the stack), then after it will execute after the return statement.

for example -

func testing() err {
    x, err := doSomething();
    if err != nil {
       return;
    }
    defer fmt.Println("hello")
    return nil
}

So if err != nil this defer will never execute, because program returned before the control reaches to the defer statement.

Now come to your Question (all will reach to the defer statement) 1. case, the statement stored in the stack is defer fmt.Printf("in defer: x = %d ", x) (with zero value of x)

  1. case - the statement stored in the stack is A function

defer func() { fmt.Printf("in defer: x = %d ", x) }()

Which is dependent on x (Note in the stack the defer statement is a function, and the value of a function will be assigned at the time of function execution)

  1. Case - defer fmt.Printf("in defer: x = %d ", x) with value 7