ホームページ >バックエンド開発 >Golang >Go の「append」関数でポインターを追加すると予期しない上書きが発生するのはなぜですか?

Go の「append」関数でポインターを追加すると予期しない上書きが発生するのはなぜですか?

Barbara Streisand
Barbara Streisandオリジナル
2024-12-25 03:36:17746ブラウズ

Why Does Appending Pointers in Go's `append` Function Lead to Unexpected Overwriting?

Go の「append」関数による予期しない上書きの問題

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} を出力します。この予期しない動作は、Go の動作の基本的な側面に由来しています。

for Range ループにコピー

Go は、for range ループを使用してスライスと配列を反復処理し、コピーを作成します。反復中の各要素の。このコードでは、for range ループ変数 e は配列要素 b[i] の一時コピーを表します。残念ながら、この一時変数のアドレスをスライス a に追加します。

修正

この問題を解決するには、一時的なコピーではなく、元の配列要素を使用します。インデックス i を使用するように for ループを変更することで、正しいアドレスがスライスに追加されるようになります。

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

この変更により、期待される出力は {0} {1} {2} {3 になります。 }.

動作の理由

Go に真の参照がないことが原因この行動に。参照が使用される C または Java では、ループ変数は配列要素を直接参照するため、ループ変数を介した変更が可能になります。ただし、Go では、ループ変数は参照ではなく要素のコピーを保持する別個の変数です。したがって、ループ変数に加えられた変更は、元の配列要素には反映されません。

以上がGo の「append」関数でポインターを追加すると予期しない上書きが発生するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。