Go スライスのコピーに追加すると、元のスライスも変更されるのはなぜですか?

Patricia Arquette
リリース: 2024-11-20 14:53:14
オリジナル
566 人が閲覧しました

Why does appending to a copy of a Go slice also modify the original slice?

スライスの追加と元のスライスに対するその影響について

Go でスライスを操作する場合、新しい要素を追加するために append 関数がよく使用されます。既存のスライスに。ただし、多くの開発者は、この追加操作で元のスライスも変更できることを知って驚くかもしれません。

調査中のコード

次のコード スニペットを考えてみましょう:

func someFunc(A []int) int {
    for i := 0; i < len(A); i++ {
        tempA := A // copy the slice by value

        fmt.Println("A: ", A)
        fmt.Println("tempA: ", A)
        fmt.Println()

        newArr = remove(tempA, i)

        if isAesthetic(newArr) {
            ways++
        }
    }
}

func remove(slice []int, s int) []int {
    return append(slice[:s], slice[s+1:]...)
}
ログイン後にコピー

ここで、someFunc 関数はスライス A を入力として受け取り、次に tempA という名前の A のコピーを作成してから呼び出します。 tempA から要素を削除する削除関数。動作中の関数を検査すると、次のコンソール出力に気づくかもしれません:

A:  [3 4 5 3 7]
tempA:  [3 4 5 3 7]

A:  [4 5 3 7 7]
tempA:  [4 5 3 7 7]

A:  [4 3 7 7 7]
tempA:  [4 3 7 7 7]

A:  [4 3 7 7 7]
tempA:  [4 3 7 7 7]
ログイン後にコピー

驚くべき副作用

コードが実行されると、次の内容が出力されます。 A と tempA の両方で、tempA で append が呼び出された後に元のスライス A も変更されることがわかります。 A の値によるコピーは tempA に加えられた変更から独立していると予想されるため、この動作は一見直観に反しているように見えるかもしれません。

ただし、この現象はスライスの実装方法の直接的な結果です。囲碁で。スライスは本質的に、ヘッダーと基礎となる配列へのポインターで構成される軽量のデータ構造です。ヘッダーにはスライスの長さと容量に関する情報が含まれており、ポインターはスライス内の最初の要素を指します。

A の値を tempA に割り当てると、基本的には、次を指す新しいスライス ヘッダーを作成することになります。 A と同じ基礎となる配列です。したがって、両方のスライスが同じデータを参照しているため、tempA に加えられた変更は A にも反映されます。

理解スライス ヘッダーと配列

この動作をさらに理解するには、Go でスライス ヘッダーと配列がどのように相互作用するかを理解するのに役立ちます。配列には、同じ型の要素の連続したブロックが含まれます。一方、スライスは、配列のセクションの動的なビューを提供します。これは配列内の連続した要素セットを記述しますが、基礎となる配列データを所有しません。

構文 []T{e1, e2, ..., を使用して配列からスライスを作成する場合en} を使用すると、基本的には配列の最初の要素を指す新しいスライス ヘッダーを作成することになります。スライスの長さは n に設定され、容量はスライス後の配列の残りの長さに設定されます。

同様に、構文 []T(arr) を使用してスライス ヘッダーを作成すると、 arr と同じ基礎となる配列を指すスライスを作成しています。スライスの長さは arr の長さに設定され、容量は arr の容量に設定されます。

影響とベスト プラクティス

スライスと配列の関係を理解すると、潜在的な落とし穴を回避し、より効率的な Go コードを作成するのに役立ちます。スライスを操作するときは、次の点に注意してください。

  • 同じ基礎となる配列への独立した参照を維持したい場合は、スライスを別のスライスに割り当てることは避けてください。
  • copy(dst) を使用してください。 、src) を使用して、同じ基になる配列を参照しながら、異なるヘッダーを持つ新しいスライスを作成します。
  • make 関数を使用して、特定の長さと容量のスライスを作成することを検討してください。新しい基礎となる配列。

Go スライスの内部を理解すると、コードが意図したとおりに動作することを確認しながら、その柔軟性と効率性を活用できるようになります。スライス ヘッダーと配列の微妙な違いを理解することで、Go でのスライスの技術をマスターし、この多用途なデータ構造の可能性を最大限に引き出すことができます。

以上がGo スライスのコピーに追加すると、元のスライスも変更されるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート