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

这是我的代码

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 部分和第 3 部分有什么区别?为什么第 2 部分输出“44444”而不是“43210”?


富国沪深
浏览 234回答 2
2回答

阿波罗的战车

'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 语句执行时被计算。

墨色风雨

为了加深对 的理解,我想再举一个例子,defer mechanish先按原样运行这个代码段,然后切换标记为 (A) 和 (B) 的语句的顺序,然后自己看看结果。package mainimport (    "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。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go