スライス追加での予期しない動作: 変更を懸念せずに複数のスライスを作成する方法
Go コードでスライスを操作するとき、不可解な問題が発生する可能性があります。問題: ループ内のスライスに要素を追加し、ループの結果を使用して新しいスライスを作成すると、最後の追加が前の追加のスライスをオーバーライドする可能性があります。この動作は、スライスが同じ基になる配列値を参照するために発生します。
例:
<code class="go">func create(iterations int) []int { a := make([]int, 0) for i := 0; i < iterations; i++ { a = append(a, i) } return a } func sliceFromLoop() { i := create(11) j := append(i, 100) g := append(i, 101) h := append(i, 102) fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h) }</code>
この例では、sliceFromLoop 関数はスライス i を作成し、異なるスライスを追加します。値をそれに追加し、スライス j、g、h が生成されます。ただし、3 つのスライスはすべて同じ基になる配列を指しているため、最後の追加で配列が変更されると、すべてのスライスに影響します。
解決策: 独立した変更のためのスライスのコピー
既存のスライスに基づいて複数のスライスを作成し、変更の懸念を回避する慣用的な方法は、何かを追加する前にスライスをコピーすることです。これにより、各新しいスライスが独自の基礎となる配列を持つことが保証されます。
<code class="go">func makeFromSlice(sl []int) []int { result := make([]int, len(sl)) copy(result, sl) return result }</code>
使用例:
<code class="go">func main() { i := make([]int, 0) for ii := 0; ii < 11; ii++ { i = append(i, ii) } j := append(makeFromSlice(i), 100) // works fine }</code>
この改訂された例では、 100を追加する前にスライスします。これにより、j が別の基礎となる配列を参照し、i に対する今後の変更の影響を受けないことが保証されます。
スライス リテラルの動作の説明
この問題が発生する理由スライス リテラル (例: i := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) では発生しないのは、追加操作によって新しい配列が割り当てられることです。バッキング アレイの容量を超えています。この動作はスライス リテラルとは無関係で、スライスへの追加の基本的なプロパティです。
以上がループ内のスライスに追加すると、Go の他のスライスに影響を与えるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。