Go のスライスのスライシング(部分切り出し)

スライスの一部を切り出して新しいスライスを作る操作を「スライシング」と呼びます。配列やスライスから部分的なビューを作成する基本的な操作です。

基本のスライス式

s[low:high] の形式で、インデックス low から high-1 までの要素を含む新しいスライスを作成します。

numbers := []int{0, 1, 2, 3, 4, 5}
slice := numbers[2:5]
fmt.Println(slice) // [2 3 4]

low は含まれ、high は含まれません(半開区間)。この動作は Python などの他言語と同じです。

インデックスの省略

low または high を省略できます。省略した場合、それぞれ先頭または末尾を意味します。

numbers := []int{0, 1, 2, 3, 4, 5}

fmt.Println(numbers[:3])  // [0 1 2]    先頭から3つ
fmt.Println(numbers[3:])  // [3 4 5]    3番目から末尾
fmt.Println(numbers[:])   // [0 1 2 3 4 5] 全体のコピー

s[:] は元のスライスと同じ内容のスライスを返しますが、背後の配列を共有している点に注意が必要です。

配列からスライスを作る

配列に対してスライス式を適用すると、スライスが作成されます。

arr := [5]int{10, 20, 30, 40, 50}
slice := arr[1:4]
fmt.Println(slice) // [20 30 40]

この方法で作成したスライスは、元の配列を背後の配列として共有します。

スライスしたスライスの容量

スライシングで作成したスライスの容量は、元のスライスの容量から low を引いた値になります。

original := make([]int, 5, 10)
for i := range original {
    original[i] = i
}

slice := original[2:4]
fmt.Printf("len=%d cap=%d\n", len(slice), cap(slice))
// len=2 cap=8

容量が 8 になるのは、元の容量 10 から先頭のインデックス 2 を引いた値です。

フルスライス式(3インデックス形式)

s[low:high:max] の形式を使うと、容量も制限できます。

original := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := original[2:5:7]

fmt.Println(slice)                              // [2 3 4]
fmt.Printf("len=%d cap=%d\n", len(slice), cap(slice)) // len=3 cap=5

3番目のインデックス max は、容量の上限を指定します。容量は max - low で計算されます。この例では 7 - 2 = 5 です。

フルスライス式の用途

フルスライス式は、元のスライスへの意図しない影響を防ぐために使います。

original := []int{0, 1, 2, 3, 4, 5}

// 通常のスライス:appendで元の配列に影響する可能性がある
normal := original[2:4]
normal = append(normal, 999)
fmt.Println(original) // [0 1 2 3 999 5] ← 変更される

// フルスライス式:容量を制限してappendで新しい配列を確保させる
original = []int{0, 1, 2, 3, 4, 5}
limited := original[2:4:4]
limited = append(limited, 999)
fmt.Println(original) // [0 1 2 3 4 5] ← 変更されない

容量を長さと同じに制限することで、append 時に必ず新しい配列が確保されるようになります。元のスライスを変更したくない場合に有効なテクニックです。