ホームページ > バックエンド開発 > Golang > Go `for...range` ループでポインターを追加すると予期しない結果が生じるのはなぜですか?

Go `for...range` ループでポインターを追加すると予期しない結果が生じるのはなぜですか?

Barbara Streisand
リリース: 2024-12-30 17:03:12
オリジナル
772 人が閲覧しました

Why Does Appending Pointers in a Go `for...range` Loop Produce Unexpected Results?

Go の追加に関する奇妙な動作を理解する

Go では、追加関数はスライスに対して動作して新しい要素を追加します。ただし、for range ループ内で配列の要素にポインタを追加すると、予期しない動作が発生する可能性があります。

次の例を考えてみましょう:

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 range ループが元の要素自体ではなく、要素のコピーを反復処理するために発生します。この場合、ループ変数 e は配列の現在の要素のコピーを保持します。スライスが追加されると、ループ変数のアドレスが追加され、すべての反復で同じメモリ位置を参照します。その結果、配列の最後の要素が検出されると、追加されたすべてのアドレスが同じ要素を指します。

修正

この問題を解決するには、追加関数を次のようにする必要があります。ループ変数ではなく、元の配列要素のアドレスとともに使用されます。修正されたコードは次のとおりです:

for i := range b {
    a = append(a, &b[i])
}
ログイン後にコピー

この変更により、出力は期待どおりになります: {0} {1} {2} {3}。

結論

Go におけるポインター型と非ポインター型の違いを理解することは、メモリ参照を適切に処理するために重要です。 for range ループを使用する場合は、元の要素とコピーのどちらにアクセスする必要があるかを検討し、それに応じて適切な構文を使用することが重要です。

以上がGo `for...range` ループでポインターを追加すると予期しない結果が生じるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート