如何理解 go 闭包中的作用域

how to understand scope in go closure

有谁知道为什么case1输出相同的结果,而case2输出顺序结果? 我知道case1输出相同值的原因是函数中的每个函数的闭包切片访问相同的范围。

但是为什么每次循环加上i:=i后case2都能输出顺序结果呢? eachloop 中重新定义 i 后,会生成一个新的作用域吗? 喜欢让 javascript?

案例1

func main() {
    funcs := []func() {}

    for i:=0;i<10;i++{
        funcs = append(funcs, func() {
            fmt.Println(i)
        })
    }

    for i:=0;i<10;i++{
        funcs[i]()
    }
}

输出

10
10
10
10
10
10
10
10
10
10

案例2

func main() {
    funcs := []func() {}

    for i:=0;i<10;i++{
        i := i
        funcs = append(funcs, func() {
            fmt.Println(i)
        })
    }

    for i:=0;i<10;i++{
        funcs[i]()
    }
}

输出

0
1
2
3
4
5
6
7
8
9

这实际上不是范围问题,而是编译器如何决定您的变量 i 是通过引用还是通过值捕获的问题。这并不总是显而易见的。在本例中,for 循环重用迭代变量 i。在 case1 中,变量 i 被捕获为引用,因为编译器认为它在捕获发生后发生了变化。在 case2 中,内部变量 i 在捕获、捕获和释放之前创建,因此编译器将其视为不变并按值捕获它。结果是当函数在 case1 中是 运行 时,结果都是最终值,因为这就是变量 i 最终的结果,每个函数只持有对那个特定 i 的引用。在 case2 中,每个捕获在创建时都传递了 i 的“副本”,因此它们显示了您期望的值。