Golang の奇妙な「追加」動作: スライス内の値を上書きする
Golang では、スライスに追加する場合、その違いを理解することが不可欠ですポインター型と非ポインター型の間。
例を考えてみましょう。コード:
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 ループが配列要素のコピーに対して動作するためです。
for ... 範囲を反復処理すると、一時的なループ変数が作成され、配列要素の値が割り当てられます。この場合、一時変数の型は Foo です。ただし、スライスに追加する場合、実際の配列要素のアドレスではなく、一時変数のアドレスが追加されます。
この一時変数は、ループ反復ごとに、配列の最後の要素の値で上書きされます。配列、つまり Foo{3} です。その結果、スライスには、配列の最後の要素を指す同じポインターへの参照が複数含まれています。
問題を解決するには、ループ変数の代わりに配列要素のアドレスを追加する必要があります。
for i := range b { a = append(a, &b[i]) }
この変更により、出力は期待どおりになります: {0} {1} {2} {3}。
この動作は、次の重要性を強調しています。 Go の型システムと、スライスを操作するときのポインタと非ポインタの区別を理解します。
以上がGo でスライスにポインタを追加すると、予期しない値が上書きされるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。