2014-07-05 71 views
1

当执行下面的代码时,我得到了我期望的第一个循环完成(序列从0到9)。但是,当第二循环结束,结果不是我所期待的(我希望同样的结果在第一循环中,但只打印“10片):Go func closure in loop

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 

    for i := 0; i < 10; i++ { 
     wg.Add(1) 

     go func(j int) { 
      defer wg.Done() 

      fmt.Println(j) 
     }(i) 
    } 

    wg.Wait() 

    fmt.Println("done first") 

    for i := 0; i < 10; i++ { 
     wg.Add(1) 

     go func() { 
      defer wg.Done() 

      fmt.Println(i) 
     }() 
    } 

    wg.Wait() 

    fmt.Println("done second") 
} 

输出:

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
done first 
10 
10 
10 
10 
10 
10 
10 
10 
10 
10 
done second 

为什么第二个循环不打印一个序列?

+0

阅读文档:[关闭作为goroutines运行时会发生什么?](http://golang.org/doc/faq#closures_and_goroutines) – peterSO

+0

谢谢。正在寻找'有效的去',但没有找到任何东西。所以,常见问题解答有答案。 – Kiril

回答

3

因为第一个每次都得到一个循环计数器的副本。而第二个获取作为闭包的一部分捕获的变量。

在第一个,你通过它在这里循环的每次迭代:

go func(j int) { 
    defer wg.Done() 

    fmt.Println(j) 
}(i) // <------------ its passed in here as part of each loop iteration 

第二个接收什么..所以,循环计数器i被捕获作为的一部分关闭。在第一次执行例程时,for循环已完成。循环完成已将i变量(即现在是闭包的一部分)设置为10.执行例程#1并打印值为i ..现在已经是10,其余的都跟在后面。

TLDR:这里的问题是循环在任何运行例程计划运行之前完成 - 它就那么快。因此,i == 10当go例程运行。

+0

相关文章:http://stackoverflow.com/questions/111102/how-do-javascript-closures-work – OneOfOne