Goでは、for rangeを使うと、range式から得られる値ごとにコードのブロックを繰り返せます。
range式によって、繰り返しごとに値が1つ得られるか2つ得られるかが決まります。
range式range
スライスに対するrangeは、各要素のインデックスと値を順番に返します:
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(i, v)
}
// 0 10
// 1 20
// 2 30
range
マップに対するrangeは、各キーと値を返しますが、繰り返しの順序は保証されません。
Goはマップの繰り返し順序を意図的にランダム化しているため、同じプログラムでも実行するたびに異なる出力になることがあります。
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// 99 20
// 999 30
// 9 10
range
文字列に対するrangeは、バイトインデックスと各ルーン(Unicodeコードポイント)を返します。
次の例では、子が3バイトを占めるため、猫はバイトインデックス1ではなく3から始まります。
for i, r := range "子猫" {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 3 29483 猫
代わりにルーンのインデックスが必要な場合は、文字列をルーンのスライスに変換します:
for i, r := range []rune("子猫") {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 1 29483 猫
range
rangeは整数を直接繰り返すことができ、0からその整数の手前までの値を順に返します。
0や負の値も有効ですが、繰り返しは1回も行われません。
for n := range 3 {
fmt.Println(n)
}
// 0
// 1
// 2
range
rangeは、iter.Seq[V]型またはiter.Seq2[K, V]型のイテレーターを受け付けます。
イテレーターとは、値を1つずつ順番に生み出す関数です。
rangeを使うと、それらの値を順にたどることができます。
text := "The quick brown fox"
for word := range strings.FieldsSeq(text) {
fmt.Println(word)
}
// The
// quick
// brown
// fox
names := []string{"Alice", "Bob", "Vera"}
for i, v := range slices.All(names) {
fmt.Println(i, ":", v)
}
// 0 : Alice
// 1 : Bob
// 2 : Vera
range
最後に、rangeは、チャネルがどこかで閉じられるまで、そのチャネルを通して送られてくる値を受け取ることができます。
チャネルについては、トラックのシラバスの後半でより詳しく扱います。
Goでは、宣言した変数を使わないとコンパイルできません。
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(v)
}
// Go build failed: declared and not used: i
値だけが必要な場合は、インデックスまたはキーを_に代入して無視します。
vals := []int{10, 20, 30}
for _, v := range vals {
fmt.Println(v)
}
// 10
// 20
// 30
インデックスだけが必要な場合は、値を完全に省略します:
vals := []int{10, 20, 30}
for i := range vals {
fmt.Println(i)
}
// 0
// 1
// 2
インデックスも値も必要ない場合は、どちらも省略できます:
vals := []int{10, 20, 30}
count := 0
for range vals {
count++
}
// count == 3