Golang:循環(huán)下的閉包(翻譯)

原文地址:https://github.com/golang/go/wiki/CommonMistakes#wiki-pages-box
)

Introduction(介紹)

When new programmers start using Go or when old Go programmers start using a new concept, there are some common mistakes that many of them make. Here is a non-exhaustive list of some frequent mistakes that show up on the mailing lists and in IRC.Using goroutines on loop iterator variables

當(dāng)工程師剛開始使用Go或者Go工程師剛開始接觸到一個(gè)新的概念的時(shí)候,他們中的很多人對(duì)這些概念會(huì)產(chǎn)生類似的誤解。下文就郵件列表和IRC中一些常見的問(wèn)題給出簡(jiǎn)要的解釋。迭代變量用在循環(huán)下的go協(xié)程上。

When iterating in Go, one might attempt to use goroutines to process data in parallel. For example, you might write something like this, using a closure:

當(dāng)使用Go語(yǔ)言處理迭代時(shí),有人可能會(huì)嘗試使用協(xié)程來(lái)并行處理數(shù)據(jù)。例如,你可能會(huì)使用閉包寫下面的代碼:

for _, val := range values {
    go func() {
        fmt.Println(val)
    }()
}

The above for loops might not do what you expect because their val variable is actually a single variable that takes on the value of each slice element. Because the closures are all only bound to that one variable, there is a very good chance that when you run this code you will see the last element printed for every iteration instead of each value in sequence, because the goroutines will probably not begin executing until after the loop.

以上的代碼或許不會(huì)按照你的預(yù)期運(yùn)行,因?yàn)樗麄兊膙al變量實(shí)際上是值為每一個(gè)切片元素值得單一變量。因?yàn)檫@些閉包都綁定到了這一個(gè)變量,那么很可能當(dāng)你執(zhí)行這段代碼得時(shí)候每次迭代你都只看到打印出來(lái)得序列中最后一個(gè)數(shù)值,因?yàn)閰f(xié)程很可能知道循環(huán)結(jié)束之后才會(huì)執(zhí)行。

The proper way to write that closure loop is:

正確的編寫閉包循環(huán)的方式應(yīng)該是:

for _, val := range values {
    go func(val interface{}) {
        fmt.Println(val)
    }(val)
}

By adding val as a parameter to the closure, val is evaluated at each iteration and placed on the stack for the goroutine, so each slice element is available to the goroutine when it is eventually executed.

通過(guò)將val作為一個(gè)參數(shù)添加到閉包里頭,val被取值并存放至協(xié)程的棧上,所以當(dāng)協(xié)程最終執(zhí)行的時(shí)候,每一個(gè)切片元素對(duì)協(xié)程來(lái)說(shuō)都是可用的。

It is also important to note that variables declared within the body of a loop are not shared between iterations, and thus can be used separately in a closure. The following code uses a common index variable i to create separate vals, which results in the expected behavior:

同樣值得關(guān)注的是,在循環(huán)體中被聲明的變量并不在每次的迭代中共享,因此可以被單獨(dú)的用到閉包當(dāng)中。下面的代碼使用了一個(gè)共同的索引變量i來(lái)創(chuàng)建單獨(dú)的val,這樣會(huì)產(chǎn)生預(yù)期的結(jié)果。

for i := range valslice {
    val := valslice[i]
    go func() {
        fmt.Println(val)
    }()
}

Note that without executing this closure as a goroutine, the code runs as expected. The following example prints out the integers between 1 and 10.

注意下在沒有將閉包用協(xié)程來(lái)執(zhí)行時(shí),代碼會(huì)按照預(yù)期執(zhí)行。下面的例子打印出了數(shù)字1到10.

for i := 1; i <= 10; i++ {
    func() {
        fmt.Println(i)
    }()
}

Even though the closures all still close over the same variable (in this case, i), they are executed before the variable changes, resulting in the desired behavior.

即使這些閉包們?nèi)匀唤壎ǖ酵瑯拥淖兞浚ㄔ谶@個(gè)例子中),他們卻在變量改變之前執(zhí)行,產(chǎn)生了想要的結(jié)果。

Another similar situation that you may find like following:

另外一個(gè)類似的場(chǎng)景例如如下:

for _, val := range values {
    go val.MyMethod()
}

func (v *val) MyMethod() {
        fmt.Println(v)
}

The above example also will print last element of values, the reason is same as closure. To fix the issue declare another variable inside the loop.

上面的例子同樣打印values里的最后一個(gè)元素,原因和閉包是一樣的。為了修復(fù)這個(gè)問(wèn)題,可以在循環(huán)里頭聲明另一個(gè)變量。

for _, val := range values {
        newVal := val
    go newVal.MyMethod()
}

func (v *val) MyMethod() {
        fmt.Println(v)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,870評(píng)論 0 10
  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 14,259評(píng)論 0 38
  • 唐嫣說(shuō)胡歌跟他談戀愛會(huì)有壓力 唐嫣說(shuō)胡歌: 跟他談戀愛會(huì)有壓力 以下是唐嫣對(duì)胡歌的看法: 真正認(rèn)識(shí)胡歌,是在拍《仙...
    奇聞播客閱讀 996評(píng)論 0 0
  • 尺地蹬旋雙輪飛, 淺景逢來(lái)?yè)溆巴耍?沉池仰臂蝶云翼, 淡塵悠懸劍緩歸。
    逸清漂亮閱讀 276評(píng)論 3 3
  • 說(shuō)起“談判”,你聯(lián)想到了什么呢? 是頂級(jí)寫字樓里西裝革履的精英們坐在會(huì)議室里唇槍舌戰(zhàn)的場(chǎng)景?還是談判專家與挾持人質(zhì)...
    精時(shí)力崔律閱讀 1,121評(píng)論 0 4

友情鏈接更多精彩內(nèi)容