首頁 >後端開發 >Golang >為什麼 Go 需要在閉包中明確複製循環變數?

為什麼 Go 需要在閉包中明確複製循環變數?

Barbara Streisand
Barbara Streisand原創
2024-12-24 01:44:11353瀏覽

Why Does Go Require Explicit Copying of Loop Variables in Closures?

Go 中捕獲的閉包(for 循環變數)

Go 編譯器不會自動捕獲for...range 循環變數作為本地分配閉包變數。相反,Go 類似地對待所有 for 迴圈(包括 for...range 迴圈),需要將迴圈變數明確複製到局部閉包中以確保預期的行為。

複製迴圈變數的原因

此行為源自於 Go 對 for 迴圈的一致處理。在所有類型的 for 循環中,包括 for...range 循環,循環變數的作用域為循環區塊。循環塊結束後,循環變數將不再可存取。

在 for...range 迴圈中,循環變數在迴圈的每次迭代中都會被初始化為新值。但是,在循環內建立的閉包繼續引用原始循環變數。為了確保閉包具有循環變數的獨立副本,必須將其指派給閉包內的局部變數。

程式碼範例

以下是一個範例這說明了複製循環變數的必要性:

func main() {
    m := make(map[int32]int32)
    for i := int32(1); i <= 10; i++ {
        m[i] = i
    }

    l := make([]func() (int32, int32), 0)
    for k, v := range m {
        l = append(l, func() (int32, int32) {
            return k, v
        })
    }

    for _, f := range l {
        k, v := f()
        fmt.Println(k, v)
    }
}

在此範例中,循環變數k 預計在for...range 的每次迭代期間發生變化環形。然而,閉包捕獲了原始循環變數 k,該變數在整個循環中保持不變。結果,代碼列印同一對值 (10, 10) 十次。

解:複製循環變數

要解決此問題,循環變數必須複製到閉包內的局部變數:

func main() {
    m := make(map[int32]int32)
    for i := int32(1); i <= 10; i++ {
        m[i] = i
    }

    l := make([]func() (int32, int32), 0)
    for k, v := range m {
        kLocal, vLocal := k, v
        l = append(l, func() (int32, int32) {
            return kLocal, vLocal
        })
    }

    for _, f := range l {
        k, v := f()
        fmt.Println(k, v)
    }
}

現在,閉包會擷取局部變數kLocal 和vLocal,它獨立地保存在for...range 循環的每次迭代期間分配的值。代碼正確列印了預期的值對 (1, 1), (2, 2), ..., (10, 10)。

以上是為什麼 Go 需要在閉包中明確複製循環變數?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn