首頁 >後端開發 >Golang >為什麼 Go 的「append」函數在從 for-range 迴圈追加指標時會產生意外結果?

為什麼 Go 的「append」函數在從 for-range 迴圈追加指標時會產生意外結果?

Linda Hamilton
Linda Hamilton原創
2024-12-22 22:35:15807瀏覽

Why does Go's `append` function produce unexpected results when appending pointers from a for-range loop?

Go 切片的意外追加行為:解釋

在 Go 中,append 函數在追加到指標切片時的行為很有趣。為了說明這一點,請考慮以下程式碼:

import "fmt"

type Foo struct {
    val int
}

func main() {
    var a = make([]*Foo, 1)
    a[0] = &Foo{0}

    var b = [3]Foo{Foo{1}, Foo{2}, Foo{3}}
    for _, e := range b {
        a = append(a, &e)
    }

    for _, e := range a {
        fmt.Printf("%v ", *e)
    }
}

與人們預期的程式碼會列印{0} {1} {2} {3} 相反,它反而列印{0} {3} { 3} {3}。這種差異背後的原因在於 for 迴圈範圍變數的性質。

理解範圍變數

Go 中的 for-range 迴圈會透過建立一個副本來操作正在迭代的陣列或切片中的每個元素。在本例中,e 是數組 b 中元素的副本。因此,e 本身不是 b 中的元素;相反,它是保存元素值的臨時變數。

追加到切片 a 時,程式碼追加的是 e 的位址,而不是 b 中實際元素的位址。由於 e 對於所有迭代都是相同的副本,因此相同的指標會被附加到 a 三次。因此,分配給 e 的最後一個值(即 Foo{3})是重複列印的值。

修復行為

要修正此行為,程式碼應附加 b 中實際元素的位址,而不是 e 的位址。修正後的循環如下所示:

for i := range b {
    a = append(a, &b[i])
}

透過附加 &b[i] 而不是 &e,程式碼確保 b 中的每個元素都加到 a 中。因此,會印出正確的輸出 {0} {1} {2} {3}。

初始行為的原因

此意外行為源自於缺少Go 中的真實引用。 Go 有指標型別和非指標型,但沒有引用。範圍變數只是一個局部變量,保存的值可以是指標或非指標。它不能保存引用。

因此,在操作範圍變數時,只是操作值,而不是操作元素本身。要修改實際元素,必須將值指派給範圍變量,從而有效地複製該值。然後該值將在下一次迭代中被覆蓋。

以上是為什麼 Go 的「append」函數在從 for-range 迴圈追加指標時會產生意外結果?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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