小编典典

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

go

这是我的代码(运行):

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”?


阅读 294

收藏
2020-07-02

共1个答案

小编典典

“第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语句时,将 评估 “ defer f(e)”中的表达式“ e” 。

2020-07-02