我有一个关于golang延迟的问题:golang延迟语句是在return语句之前还是之后执行?
我已经阅读Defer_statements。但是我没有答案。
我做了一个简单的测试:
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())
}
Run Code Online (Sandbox Code Playgroud)
在中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
Run Code Online (Sandbox Code Playgroud)
那么,有谁能解释:1.为什么得到这个结果?为什么test1打印0,test2打印9,test3打印7。2.延迟语句在返回之后还是返回之前执行?
非常感谢。
Jam*_*Shi 12
感谢@dev.bmax @Tranvu Xunnhat @rb16。在您的帮助下,我从Defer_statements 中找到了关键解释。
每次执行“defer”语句时,函数值和调用的参数都会像往常一样评估并重新保存,但不会调用实际的函数。
我们可以defer ...分成三个部分。
我做了一个新的test4来解释。
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
}
Run Code Online (Sandbox Code Playgroud)
在测试 4 中,
func(n int)(0)堆栈。func(n int)(0)之后执行return 9,n infmt.Printf("in defer x as parameter: x = %d\n", n)已经被求值,x infmt.Printf("in defer x after return: 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
Run Code Online (Sandbox Code Playgroud)
在第一个x测试中,当包含运行的行时评估参数的值defer。它发生在第 1 行,此时x仍为 0。
请注意,即使fmt.Printf稍后调用,它的参数也会提前评估。
在第三个测试中,在语句运行之前将参数的值x设置为 7 defer。同样,这发生在实际调用之前fmt.Printf。
第二次测试有点不同。变量x在匿名函数的范围内。它的值在函数运行时评估,这在测试函数返回时发生。到时候x已经9点了。
小智 5
我将参考Defer_statements来解释你的结果。
问题2:defer返回后执行。
问题1:来自文档
每次执行“defer”语句时,调用的函数值和参数都会照常评估并重新保存,但不会调用实际函数。
测试 1:Defer 调用 fmt.Println。fmt.Println 计算 x 的值,即 0(零值)。test1() 在主函数中返回 9。
测试 2:Defer 调用 func() {}。fmt.Println 仅在执行 func() {} 时(返回后)计算 x。因此,x 的计算结果为 9。 test2() 在主函数中返回 9。
测试 3:Defer 调用 fmt.Println。fmt.Println 计算 x 的值,即 7(x 被分配给 7)。test3() 在主函数中返回 9。
不是之前或之后,而是关于 defer 语句是否存在于堆栈中。如果是(如果控制到达 defer 语句,它将 store 语句保存到堆栈中),那么 after 它将在 return 语句之后执行。
例如 -
func testing() err {
x, err := doSomething();
if err != nil {
return;
}
defer fmt.Println("hello")
return nil
}
Run Code Online (Sandbox Code Playgroud)
因此,如果 err != nil这个 defer 永远不会执行,因为程序在控制到达 defer 语句之前返回。
现在回答你的问题(所有问题都会到达 defer 语句) 1. 情况下,存储在堆栈中的语句是defer fmt.Printf("in defer: x = %d\n", x)(x 值为零)
defer func() {
fmt.Printf("in defer: x = %d\n", x)
}()
取决于x(注意栈中的defer语句是一个函数,函数的值会在函数执行的时候被赋值)
defer fmt.Printf("in defer: x = %d\n", x)值为 7