配列は固定サイズでありそれはそのタイプの一部です。スライスは基盤となる配列の柔軟で動的なビューです。実際には、ほぼ常にスライスを使用します。配列は日常的なGoではまれです。
配列 — 固定サイズ
arr []
arr[] =
fmt.Println((arr))
配列のサイズはコンパイル時に固定されており、そのタイプの一部です([5]int ≠ [3]int)。配列は値型でもあります。割り当てたり渡したりすると、配列全体がコピーされます。この硬さがそれらがめったに直接使用されない理由です。
s := []int{1, 2, 3} // a slice (no size in the brackets)
s = append(s, 4) // grow it — append returns a new slice
fmt.Println(len(s), cap(s)) // length and capacity
nums := make([]int, 0, 10) // make a slice: length 0, capacity 10 (pre-allocated)
スライスは固定サイズではありません。appendで拡張します。これは使うべき動的シーケンスです。
A slice is a small struct: { pointer to underlying array, length, capacity }
- len = number of elements currently in the slice
- cap = size of the underlying array from the slice's start
append: if len < cap, reuses the array; if len == cap, allocates a BIGGER array & copies
original := []int{1, 2, 3, 4, 5}
sub := original[1:3] // [2, 3] — a VIEW into the same backing array
sub[0] = 99 // ⚠️ also changes original[1] → [1, 99, 3, 4, 5]!
スライシング(s[low:high])はコピーしません。同じ基盤配列を指す新しいスライスヘッダーを作成します。1つを変更すると他に影響する可能性があります。微妙なバグの一般的な原因です。独立したコピーにはcopy()を使用してください。
a := []int{1, 2, 3}
b := append(a, 4) // may or may not share a's array depending on capacity
// safe pattern: always use the RETURNED slice from append
a = append(a, 4)
スライスはGoで最も使用される機能の1つであり、最も誤解される機能の1つです。
配列が固定サイズの値型(めったに直接使用されない)であること、一方スライスがバッキング配列への柔軟で参照のようなビュー(日常的なツール)であることを理解することは基本的です。
重要なことに、共有バッキング配列の動作を知ること。スライシングはビューを作成し、コピーではなく、修正が他のスライスに影響する可能性があること、そしてappendは再割り当てするかもしれないし、しないかもしれないこと。これは経験豊富な開発者でさえも捕捉する微妙で、デバッグが難しいエイリアシングバグのクラスを防ぎます。
スライスをマスターすること(len vs cap、append、copy、共有の落とし穴)は日常的なGo知識が不可欠であり、ほぼすべてのコレクション作業でそれらを使用するため、頻繁なインタビューのトピックです。