如何理解 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
的“副本”,因此它们显示了您期望的值。
有谁知道为什么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
的“副本”,因此它们显示了您期望的值。