这是我的代码(run):
package main
import "fmt"
func main() {
var whatever [5]struct{}
for i := range whatever {
fmt.Println(i)
} // part 1
for i := range whatever {
defer func() { fmt.Println(i) }()
} // part 2
for i := range whatever {
defer func(n int) { fmt.Println(n) }(i)
} // part 3
}
输出:
0
1
2
3
4
4
3
2
1
0
4
4
4
4
4
问题:第2部分和第2部分之间有什么区别?第3部分?为什么第2部分输出“44444”而不是“43210”?
答案 0 :(得分:36)
'part 2'闭包捕获变量'i'。当闭包(后面)中的代码执行时,变量'i'具有它在range语句的最后一次迭代中具有的值,即。 '4'。因此
4 4 4 4 4
输出的一部分。
'part 3'不会捕获其闭包中的任何外部变量。正如specs所说:
每次执行“defer”语句时,将像往常一样评估调用的函数值和参数,并重新保存但不调用实际函数。
因此每个deferred函数调用都具有不同的'n'参数值。它是执行延迟语句时'i'变量的值。因此
4 3 2 1 0
部分输出因为:
...延迟调用在周围函数返回之前立即以LIFO顺序执行...
需要注意的关键点是,当延迟语句执行时,'defer f()'中的'f()'不是执行
<强>但强>
当defer语句执行时,'defer f(e)'中的表达式'e'被评估。
答案 1 :(得分:0)
我想提出另一个示例,以增进对defer mechanish
的理解,首先运行此代码段,然后切换标记为(A)和(B)的语句的顺序,然后查看结果给自己。
package main
import (
"fmt"
)
type Component struct {
val int
}
func (c Component) method() {
fmt.Println(c.val)
}
func main() {
c := Component{}
defer c.method() // statement (A)
c.val = 2 // statement (B)
}
我一直想知道在这里适用哪些正确的关键字或概念。看起来表达式c.method
已被求值,因此返回了绑定到组件“ c”的实际状态的函数(如获取组件内部状态的快照)。
我想答案不仅涉及defer mechanish
,还涉及funtions with value or pointer receiver
的工作方式。请注意,还会发生以下情况:如果将名为method
的功能更改为pointer receiver
,则延迟将c.val打印为2,而不是0。