INDEX
rangeの概要
データ構造の反復処理 Goの予約語 | ||
range 概要 |
||
|
スライスと配列のrangeループ
スライスや配列に対してrange
を使うと、インデックスと値の2つの変数を受け取れます。
package main
import "fmt"
func main() {
numbers := []int{10, 20, 30, 40}
for index, value := range numbers {
fmt.Printf("インデックス: %d, 値: %d\n", index, value)
}
}
解説:
range numbers
を使うと、スライスの各要素を順番に処理できる。index
にはインデックスが、value
には要素の値が入る。
実行結果:
インデックス: 0, 値: 10 インデックス: 1, 値: 20 インデックス: 2, 値: 30 インデックス: 3, 値: 40
インデックスを無視する
インデックスが不要な場合は、アンダースコア(_
)を使って無視できます。
package main
import "fmt"
func main() {
numbers := []int{10, 20, 30, 40}
for _, value := range numbers {
fmt.Println("値:", value)
}
}
解説:
_
を使うことで、インデックスを無視できる。- 変数を省略することで、不要な変数を定義せずに済む。
実行結果:
値: 10 値: 20 値: 30 値: 40
マップのrangeループ
マップに対してrange
を使うと、キーと値のペアを取得できます。
package main
import "fmt"
func main() {
ages := map[string]int{"太郎": 25, "花子": 30, "次郎": 20}
for key, value := range ages {
fmt.Printf("名前: %s, 年齢: %d\n", key, value)
}
}
解説:
- マップを
range
で反復処理すると、キーと値を取得できる。 - マップの順序は保証されないため、出力順は実行ごとに異なる可能性がある。
実行結果(順序はランダム):
名前: 花子, 年齢: 30 名前: 太郎, 年齢: 25 名前: 次郎, 年齢: 20
キーまたは値を無視する
キーまたは値が不要な場合も、アンダースコア(_
)を使って無視できます。
package main
import "fmt"
func main() {
ages := map[string]int{"太郎": 25, "花子": 30, "次郎": 20}
// 値のみ使用
for _, value := range ages {
fmt.Println("年齢:", value)
}
// キーのみ使用
for key := range ages {
fmt.Println("名前:", key)
}
}
解説:
for _, value := range ages
でキーを無視して値のみ取得。for key := range ages
で値を無視してキーのみ取得。
文字列のrangeループ(rune単位)
文字列に対してrange
を使うと、各文字(rune)を取得できます。
package main
import "fmt"
func main() {
str := "こんにちは"
for index, char := range str {
fmt.Printf("インデックス: %d, 文字: %c\n", index, char)
}
}
解説:
range
を使うと、UTF-8の各文字(rune)を取得できる。- マルチバイト文字(日本語など)は、1文字が1バイトとは限らない。
実行結果:
インデックス: 0, 文字: こ インデックス: 3, 文字: ん インデックス: 6, 文字: に インデックス: 9, 文字: ち インデックス: 12, 文字: は
チャネルのrangeループ
チャネルをrange
で反復処理すると、送信された値を受信し続けることができます。
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 10
ch <- 20
ch <- 30
close(ch) // チャネルをクローズ
for val := range ch {
fmt.Println("受信:", val)
}
}
解説:
- チャネルがクローズされるまで、
range
で値を受信し続ける。 - クローズされると
range
ループが自動的に終了する。
実行結果:
受信: 10 受信: 20 受信: 30
注意事項
- マップの順序は保証されない: ループごとに異なる順番で処理される可能性がある。
- 文字列のrangeはバイト単位ではなくrune単位: 日本語などのマルチバイト文字を正しく処理できる。
- チャネルのrangeはクローズを検知: クローズされるまでループし続ける。
よくある質問
- Q: rangeを使うと配列やスライスのコピーが作成されますか?
- A: いいえ。rangeは要素へのアクセスを提供するだけで、新しいコピーを作成しません。
- Q: マップのrangeの順序は一定ですか?
- A: いいえ。Goのマップは順序が保証されていないため、実行するたびに異なる順番で出力される可能性があります。
- Q: 文字列をrangeでループすると、なぜインデックスが飛ぶのですか?
- A: 文字列はUTF-8エンコードされており、マルチバイト文字(日本語など)は1文字が1バイトとは限らないためです。
- Q: rangeでスライスを変更できますか?
- A: 可能ですが、ループ内で値を変更しても元のスライスには反映されません。スライスのインデックスを使って変更する必要があります。
- Q: チャネルのrangeはいつ終了しますか?
- A: チャネルが明示的に
close()
されたときにループが終了します。未クローズのチャネルをrangeでループすると、データが送信されるまでブロックされ続けます。
まとめ
range
を使うと、スライス、配列、マップ、チャネルを簡単に反復処理できる。- スライスや配列では、インデックスと値を取得できる。
- マップでは、キーと値を取得できるが、順序は保証されない。
- 文字列のrangeはrune単位で処理され、マルチバイト文字に対応している。
- チャネルのrangeは、チャネルがクローズされるまで値を受信し続ける。