2014-07-05 97 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