Goでは、構造体は値によってコピーされます(最初のレベルでのディープコピー、ネストされた構造体も同様のルールでコピーされます)。一方、スライスは値としてコピーされますが、コピーされるのは構造体のみで、データの元の配列はコピーされません。オリジナルとコピーされたスライスは同じバックアップ配列を指しているため、一方のスライスを介して変更を行うと、もう一方にも反映されます。配列の明示的なコピーを行うにはcopy()を使用します。
スライスのコピーの例:
s1 := []int{1,2,3} s2 := s1 // 同じバッファを指す! s2[0] = 99 fmt.Println(s1) // [99 2 3] // 配列のコピーを作成するには: s3 := make([]int, len(s1)) copy(s3, s1) s3[0] = 42 fmt.Println(s1) // [99 2 3], s3は独立している
構造体をコピーする際、構造体がポインタフィールドまたはスライスフィールドを含む場合、コピーされるのは参照のみで、値はコピーされません。
変更がオリジナルに影響を与えないようにスライスを「クローン」する方法は?
誤った答え:単にb := aとすること。正しい方法は:
copyを使用して、新しいスライスを必要な長さで作成し、データをコピーすること:newS := make([]int, len(a)) copy(newS, a)
物語
説明: 動的にリクエストのスライスフィールドを変更してDBへリクエストを生成しており、コピーを作成しなかった。再利用されたリクエストではデータが交差し、ユーザーに不正確な結果を返していた。
物語
説明: データを並行処理する際に、代入によって構造体のコピーを作成し、一方のゴルーチンでスライスを拡張し、他方で元のスライスを並行して使用していた。データが「上書き」され、予測不可能なバグが発生した。
物語
説明: バッファ構造体を使用しており、代入による同時コピーはネストされたスライスを考慮していなかった(シャローコピー)。一方の場所での変更が別のバッファに影響を与え、データの変更元を追跡するのが難しくなった。