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 サイトの他の関連記事を参照してください。