Go のスライスのイテレーション(for range)
スライスの全要素を順番に処理するには、for range を使います。Go でスライスをループ処理する最も一般的な方法です。
基本的な for range
for range はスライスの各要素に対して、インデックスと値を返します。
fruits := []string{"apple", "banana", "cherry"}
for i, v := range fruits {
fmt.Printf("%d: %s\n", i, v)
}
// 0: apple
// 1: banana
// 2: cherryi にはインデックス、v には要素の値が代入されます。
インデックスのみ使う
値が不要な場合は、値の変数を省略できます。
fruits := []string{"apple", "banana", "cherry"}
for i := range fruits {
fmt.Printf("Index: %d\n", i)
}1つの変数だけで range を受けると、インデックスが代入されます。
値のみ使う
インデックスが不要な場合は、ブランク識別子 _ を使って無視します。
fruits := []string{"apple", "banana", "cherry"}
for _, v := range fruits {
fmt.Println(v)
}
// apple
// banana
// cherryGo では使わない変数を宣言するとコンパイルエラーになるため、_ で明示的に捨てる必要があります。
値はコピーされる
for range で取得する値は、元の要素のコピーです。ループ内で値を変更しても、元のスライスには影響しません。
numbers := []int{1, 2, 3}
for _, v := range numbers {
v = v * 10 // コピーを変更しているだけ
}
fmt.Println(numbers) // [1 2 3](変更されない)元のスライスを変更したい場合は、インデックスを使って直接アクセスします。
numbers := []int{1, 2, 3}
for i := range numbers {
numbers[i] = numbers[i] * 10
}
fmt.Println(numbers) // [10 20 30]通常の for ループとの比較
for range の代わりに、通常の for ループも使えます。
for range
簡潔で読みやすい。インデックスと値を同時に取得できる。
for i := 0; i < len(s); i++
インデックスを自由に制御できる。逆順や飛ばしループに向く。
numbers := []int{1, 2, 3, 4, 5}
// 逆順で処理
for i := len(numbers) - 1; i >= 0; i-- {
fmt.Println(numbers[i])
}
// 1つ飛ばしで処理
for i := 0; i < len(numbers); i += 2 {
fmt.Println(numbers[i])
}特殊な順序で処理したい場合は、通常の for ループが適しています。
ループ中の要素追加に注意
for range の開始時にスライスの長さが決まるため、ループ中に要素を追加しても、追加した要素は処理されません。
numbers := []int{1, 2, 3}
for i, v := range numbers {
if i == 0 {
numbers = append(numbers, 4, 5)
}
fmt.Println(v)
}
// 1
// 2
// 3
// (4, 5 は出力されない)ループ開始時の長さ(3)で繰り返しが決まるため、途中で追加した要素は処理対象になりません。ループ中にスライスを変更する場合は、この挙動を理解しておく必要があります。