0

Does anybody know why the case1 output the same result, but the case2 output the sequential result? I know the reason why case1 output the same value is that the closure of each function in functions slice access to the same scope.

But why after adding i:=i in each loop can case2 output the sequential result? Does after redefining i in eachloop, a new scope is generated? like let in javascript?

case1

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]()
    }
}

output

10
10
10
10
10
10
10
10
10
10

case2

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]()
    }
}

output

0
1
2
3
4
5
6
7
8
9
Zhongwei Xu
  • 147
  • 9
  • 1
    *Scope* is related, but is the wrong term to use here. An `i := i` is a *short declaration* that creates a new `i`, so yes, this is a bit like `let` in Javascript. The *scope*, however, is there regardless of whether there's an inner declaration. The later reference to `i` uses the innermost scope `i` available. Without the short declaration, that's the outer `i`; with it, that's the inner `i`. – torek Aug 03 '21 at 06:09
  • 1
    See https://stackoverflow.com/q/52980172/13860 – Jonathan Hall Aug 03 '21 at 07:08
  • 1
    Does this answer your question? [Captured Closure (for Loop Variable) in Go](https://stackoverflow.com/questions/26692844/captured-closure-for-loop-variable-in-go) –  Aug 03 '21 at 08:40
  • Thanks you so much for your info – Zhongwei Xu Aug 03 '21 at 10:45

1 Answers1

1

This isn't really a scope issue but rather an issue with how the compiler decides if your variable i is captured by reference or by value. This is not always obvious. For loops in go reuse the iteration variable in this case the i. In case1 the variable i is captured as a reference as the compiler sees it as being changed after the capture has taken place. In case2 the inner variable i is created before the capture, captured and released thus the compiler sees it as unchanging and captures it by value. The result is when the functions are run in case1 the results are all the final value as that is what the variable i ended up as and each function only holds a reference to that particular i. In case2 each capture was passed a "copy" of i at the time of creation thus they show the values you expect.

Olaf Bogus
  • 26
  • 3