{}const=>[]async()letfn</>var
開発

顕微鏡下のスライス:容量、コピー、成長、Goのトラップ

Goのスライスの内部構造を分析します。構造、容量が決定する理由、共有配列の危険性、隠れたバグを回避する方法について説明します。

К

Kodik

著者

1分で読める

Goのスライスは、言語の最も強力で、同時に最も危険なツールの1つです。一見すると、単なる「動的配列」のように見えますが、その下には十分なニュアンスが隠されており、1行のコードがバグになり、デバッグには数時間かかります。実際にどのように機能するかを見てみましょう。

スライスの構成

Goのスライスは配列ではありません。これは、以下を保存する「薄い包み紙」です。

  • 配列ポインタ — データの実際の保存場所。

  • 長さ(len) — 現在利用可能な要素の数。

  • 容量(キャップ) - メモリを再割り当てせずに収容できる要素の数。

 s := []int{1, 2, 3, 4}
 fmt.Println(len(s)) // 4
 fmt.Println(cap(s)) // 4
🔥 10万人以上の学生が参加中

理論を読むのに疲れた?
コーディングの時間だ!

Kodik — 実践でプログラミングを学ぶアプリ。AIメンター、インタラクティブなレッスン、実際のプロジェクト。

🤖 AI 24時間
🎓 修了証
💰 無料
🚀 始める
今日参加

キャパシティとその役割

容量は在庫です。appendを実行すると、Goは以下をチェックします。

  • 容量が十分な場合、新しい要素は同じ配列に書き込まれます。

  • キャパシティがなくなった場合、Goは 新しいより大きな配列 古いデータをそこにコピーします。

 s := make([]int, 2, 4) // len=2, cap=4
 s = append(s, 10, 20)  // まだ空きがあります
 fmt.Println(cap(s))    // 4
 s = append(s, 30)      // キャップがなくなりました → 新しい配列
 fmt.Println(cap(s))    // 8

コピーと落とし穴

copy関数は、表面コピーを実行します。

 a := []int{1, 2, 3}
 b := make([]int, len(a))
 copy(b, a)
 b[0] = 99
 fmt.Println(a) // [1 2 3]
 fmt.Println(b) // [99 2 3]

しかし、単に割り当てる場合:

 a := []int{1, 2, 3}
 b := a
 b[0] = 99
 fmt.Println(a) // [99 2 3] ❗

ここでは、ab は同じ配列を指しています。これは初心者がよく犯す間違いです。

成長:スライスの成長方法

Goは正確な成長アルゴリズムを保証するものではありませんが、通常は次のように動作します。

  • 容量が小さい場合は2倍になります。

  • 容量がすでに大きい場合は、約25%増加します。

👉したがって、ビッグデータを扱う場合は、必要なマージンを使用してmake([]T, 0, N)を事前に割り当てることをお勧めします。

落とし穴:開発者が最も頻繁に燃える場所

  1. 一般的な基礎配列

     a := []int{1, 2, 3, 4, 5}
     b := a[:3]
     c := a[2:]
     c[0] = 99
     fmt.Println(b) // [1 2 99] 😱

    bcは同じ配列を使用します。

  2. 成長は「繋がり」を壊します

     a := []int{1, 2, 3}
     b := a
     a = append(a, 4) // キャップがなくなりました → 新しい配列
     b[0] = 99
     fmt.Println(a) // [1 2 3 4]
     fmt.Println(b) // [99 2 3]

    成長後、aはすでに別の配列を持ち、bとの関係は失われました。

  3. 大きな配列のスライス

     big := make([]byte, 1e6)
     small := big[:1]
     // smallは小さく見えますが、メモリ内のすべてのメガバイトを保持します

    解決策: copy を新しいスライスに。

合計

Go のスライスは便利なツールですが、

  • 容量と成長を忘れないでください。

  • 独立したデータが必要な場合は copy を使用してください。

  • 「カットからのカット」には注意してください。

内部の仕組みを理解することで、予期しないバグを回避し、より信頼性の高いコードを書くことができます。

🎯先延ばしをやめよう

記事は気に入った?
実践の時間だ!

Kodikでは読むだけでなく、すぐにコードを書く。理論 + 実践 = 本当のスキル。

即座に実践
🧠AIがコードを説明
🏆修了証

登録不要 • カード不要