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

golang defer语句是在return语句之前还是之后执行的?,go,Go,我有一个关于golang defer的问题:golang defer语句是在return语句之前还是之后执行的? 我读过。但我没有得到答案 我做了一个简单的测试: func test1() (x int) { defer fmt.Printf("in defer: x = %d\n", x) x = 7 return 9 } func test2() (x int) { defer func() { fmt.Printf("in defer:

我有一个关于golang defer的问题:golang defer语句是在return语句之前还是之后执行的?

我读过。但我没有得到答案

我做了一个简单的测试:

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

    x = 7
    return 9
}

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

    x = 7
    return 9
}

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

func main() {
    fmt.Println("test1")
    fmt.Printf("in main: x = %d\n", test1())
    fmt.Println("test2")
    fmt.Printf("in main: x = %d\n", test2())
    fmt.Println("test3")
    fmt.Printf("in main: x = %d\n", test3())
}
test1()
中,使用
Printf
在延迟后打印x。 在
test2()
中,使用匿名函数在延迟后打印x。 在
test3()
中,使用
Printf
在延时后打印x,但在
x=7
后进行延时

但结果是:

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
那么,任何人都可以解释: 1.为什么会有这样的结果?为什么test1打印0,test2打印9,test3打印7。 2.延期声明是在返回后执行还是在返回前执行


非常感谢。

第一次测试中,当包含
延迟
的行运行时,将评估参数
x
的值。当
x
仍然为0时,它发生在第1行

请注意,即使以后会调用
fmt.Printf
,它的参数也会提前评估

第三个测试中,
x
参数的值在
defer
语句运行之前设置为7。同样,这发生在实际调用
fmt.Printf
之前

第二次测试有点不同。变量
x
在匿名函数的范围内。它的值在函数运行时计算,测试函数返回时会发生这种情况。到那时,
x
是9。

我将参考以解释您的结果

问题2:返回后执行延迟

问题1:来自文档

每次执行“defer”语句时,调用的函数值和参数都会像往常一样求值并重新保存,但不会调用实际函数

  • 测试1:延迟调用fmt.Println。Println计算x的值,即0(零值)。test1()在主函数中返回9

  • 测试2:延迟调用func(){}。当执行func(){}时(返回后),fmt.Println仅计算x。因此,x被计算为9。test2()在主函数中返回9

  • 测试3:延迟调用fmt.Println。Println计算x的值,即7(x被指定为7)。test3()在主函数中返回9


这不是在堆栈之前或之后,而是关于延迟语句是否存在于堆栈中。 如果是(如果控件到达defer语句,它会将语句保存到堆栈中),那么after将在return语句之后执行

例如—

func testing() err {
    x, err := doSomething();
    if err != nil {
       return;
    }
    defer fmt.Println("hello")
    return nil
}
所以如果
err!=nil
此延迟将永远不会执行,因为程序在控件到达延迟语句之前返回

现在来回答你的问题(所有问题都将涉及延期声明) 1.在这种情况下,存储在堆栈中的语句是
defer fmt.Printf(“在defer:x=%d\n,x中)
(0值为x)

  • 大小写-堆栈中存储的语句是一个函数
  • defer func(){
    fmt.Printf(“在延迟中:x=%d\n”,x)
    }()

    它依赖于x(注意,在堆栈中,defer语句是一个函数,函数的值将在函数执行时赋值)

  • 大小写-
    延迟fmt.Printf(“在延迟中:x=%d\n”,x)
    值为7

  • 谢谢@dev.bmax@Tranvu xunnhat@rb16。在你的帮助下,我从中找到了关键的解释

    每次执行“defer”语句时,调用的函数值和参数都会像往常一样求值并重新保存,但不会调用实际函数

    我们可以将延迟分为三部分

  • 调用defer,计算函数参数的值
  • 执行defer,将函数推入堆栈
  • 在返回或死机后执行堆栈中的函数
  • 我做了一个新的测试来解释

    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
    }
    
    在测试4中

  • 调用defer,计算n的值,n=x=0,使x作为参数为0
  • 执行延迟,将
    func(n int)(0)
    推到堆栈上
  • 执行
    func(n int)(0)
    return 9
    之后,在
    fmt.Printf中的n(“在defer x中作为参数:x=%d\n,n)”已被计算,在
    fmt.Printf中的x(“在defer x中返回后:x=%d\n”,x)
    现在将被计算,x是9
  • 所以,得到了结果:

    test4
    in defer x as parameter: x = 0
    in defer x after return: x = 9
    in main: x = 9
    
    试试这个代码

    go run test.go 
    1
    [2]
    
    test_defer return 1,因此在返回后执行defer

    go run test.go 
    1
    [2]