为了账号安全,请及时绑定邮箱和手机立即绑定

golang 的“defer”如何捕获闭包的参数?

golang 的“defer”如何捕获闭包的参数?

Go
富国沪深 2021-06-03 10:47:38
这是我的代码package mainimport "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}输出:012344321044444问题:第 2 部分和第 3 部分有什么区别?为什么第 2 部分输出“44444”而不是“43210”?
查看完整描述

2 回答

?
阿波罗的战车

TA贡献1862条经验 获得超6个赞

'part 2' 闭包捕获变量 'i'。当闭包中的代码(稍后)执行时,变量 'i' 具有它在 range 语句的最后一次迭代中的值,即。'4'。因此

4 4 4 4 4

输出的一部分。

“第 3 部分”在其闭包中没有捕获任何外部变量。正如规格所说:

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

所以每个延迟的函数调用都有不同的“n”参数值。它是执行 defer 语句时 'i' 变量的值。因此

4 3 2 1 0

输出的一部分,因为:

...在周围函数返回之前立即以 LIFO 顺序执行延迟调用 ...


需要注意的关键点是在 defer 语句执行时没有执行'defer f()' 中的 'f()'

'defer f(e)' 中的表达式 'e' 在defer 语句执行时被计算


查看完整回答
反对 回复 2021-06-07
?
墨色风雨

TA贡献1853条经验 获得超6个赞

为了加深对 的理解,我想再举一个例子,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工作。请注意,如果您将 func 命名method为 a ,则也会发生这种情况,pointer receiverdefer 会将 c.val 打印为 2,而不是 0。


查看完整回答
反对 回复 2021-06-07
  • 2 回答
  • 0 关注
  • 233 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信