下面两个代码看起来差不多,但运行结果却天差地别
代码 1
var a int
defer func() {
fmt.Println(a)
}()
for {
if a > 10 {
return
}
a++
}
代码 2
var a int
defer fmt.Println(a)
for {
if a > 10 {
return
}
a++
}
结果:
代码 1 输出:11
代码 2 输出:0
![]() |
1
Asakijz 59 天前 ![]() 可以参考下我之前提问的
https://www.v2ex.com/t/868146#reply11 |
2
SimbaPeng 59 天前
a 的求值时间
|
3
sduoduo233 59 天前 via Android
defer 的参数会提前求值
A defer statement defers the execution of a function until the surrounding function returns. The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns. |
4
dilu 59 天前 via Android
斗胆分析一下,第一种写法明显是在 func 结构体引用了一个外部变量,典型的闭包问题。而第二种写法的 defer 只是一个表达式,编译后只是一个简单的 funval 而没有对应的捕获列表。第一种写法在主函数执行完开始执行 defer 函数的时候,加载了这个 func 的 funcval 和捕获列表,其中对于 a 的引用是地址的形式,此时 a 是 10 故而打印了 10 。
|
5
extrem 59 天前
defer 语句将函数的执行推迟到周围的函数返回。
延迟调用的参数会立即计算,但在周围的函数返回之前不会执行函数调用。 |
6
dobelee 59 天前
存在传入局部变量时都用匿名函数。
一般只有简单的关闭操作才会直接写表达式,比如 defer x.Close() defer cancel() |
8
0x90200 58 天前
|
![]() |
9
supuwoerc 58 天前
这是一个闭包吧~
|
![]() |
10
supuwoerc 58 天前
找了一下我当初写的 Demo:
```go package main import "fmt" func main() { Demo1() fmt.Println("----------") Demo2() fmt.Println("----------") Demo3() } func Demo1() { for i := 0; i < 3; i++ { defer func() { fmt.Println(i) // 每次循环的 i 都是同一个 i(demo1 函数作用域中的 i ,这个上下文中的 i 在函数执行前 i 已经自增加到 3) }() } } func Demo2() { for i := 0; i < 3; i++ { defer func(val int) { fmt.Println(val) // 函数声明时的参数,并未产生闭包,正常执行 }(i) } } func Demo3() { for i := 0; i < 3; i++ { k := i // 每次循环产生一个新的 k ,函数引用这个上下文中的 k ,后续的循环并不会修改每个上下文中的 k defer func() { fmt.Println(k) }() } } ``` |
11
wanminny 58 天前
defer 语句将函数的执行推迟到周围的函数返回。
延迟调用的参数会立即计算,但在周围的函数返回之前不会执行函数调用。 |
![]() |
12
wswch4444 58 天前
关键区别就在
defer func() { fmt.Println(a) }() defer fmt.Println(a) 一个用了闭包,一个没用,没有用的,是在 编译到这个 defer 语句就确定了 a 的数值 零值 0 用了闭包 是在 函数执行完 之后 给 a 赋值 所以是 11 |
13
dyllen 49 天前
defer 相当于把一个函数放到栈里面稍后执行,函数参数会先计算好结果再放入栈。
|