【问题标题】:how to understand scope in go closure如何理解 go 闭包中的作用域
【发布时间】:2021-10-08 07:54:58
【问题描述】:

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

但是为什么在每个循环中添加 i:=i 后 case2 可以输出顺序结果? 在每个循环中重新定义 i 之后,是否会生成一个新的范围? 像 let in 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

【问题讨论】:

  • Scope 是相关的,但在这里使用的术语是错误的。 i := i 是一个简短声明,它创建一个新的i,所以是的,这有点像Javascript 中的let。但是,无论是否有内部声明,范围 都存在。后面对i 的引用使用了可用的最内层范围i。如果没有简短的声明,那就是外部 i;有了它,这就是内在的i
  • 这能回答你的问题吗? Captured Closure (for Loop Variable) in Go
  • 非常感谢您的信息

标签: go closures


【解决方案1】:

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

【讨论】:

  • 感谢您的解释
猜你喜欢
  • 1970-01-01
  • 2011-04-09
  • 2017-05-03
  • 2021-01-05
  • 2015-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-09
相关资源
最近更新 更多