ホームページ >バックエンド開発 >Golang >Go の「append」関数が範囲ループからポインターを追加すると予期しない結果が生じるのはなぜですか?

Go の「append」関数が範囲ループからポインターを追加すると予期しない結果が生じるのはなぜですか?

Patricia Arquette
Patricia Arquetteオリジナル
2024-12-08 03:08:11144ブラウズ

Why Does Go's `append` Function Produce Unexpected Results When Appending Pointers from a Range Loop?

Go の「追加」関数での意図しない上書き

Go では、スライスへの追加の微妙な違いを調べると、予期しない結果が生じることがあります。この動作を示す例を詳しく見てみましょう。

次のコードを考えてみましょう。

import "fmt"

type Foo struct {
    val int
}

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

    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} と読みます。このパズルを解くために、「append」関数を詳しく見てみましょう。

Go では、「append」は要素を追加するスライスへのポインターを期待します。この例では、スライス「a」に「Foo」インスタンスへのポインタを正しく格納しています。

しかし、配列「b」の要素をループするときに、微妙な問題が発生します。 「範囲」構文は、実際の要素自体ではなく、各要素のコピーを反復処理します。その結果、最終反復で「Foo{3}」を指す「Foo」インスタンス「e」のコピーへのポインタを一貫して追加しています。

この動作を修正するには、以下を参照する必要があります。 「append」操作における「b」の実際の要素:

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

この変更により、「b」内の要素にポインタを直接追加できるようになり、目的の出力が得られます。 {0} {1} {2} {3}.

この動作の根本的な理由を理解することが重要です。 Go では、ポインタは値であり、データを操作するときにメモリ アドレスとして解釈されます。そのため、「range」ループは、元のオブジェクトではなく、値のコピーを反復処理します。この知識は、最初のコードで 3 つの要素が同じ "Foo{3}" インスタンスを指していた理由を理解するのに役立ちます。

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

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