Go 言語の繰返し処理 (for ループ)
Goのループ
Go で繰り返し処理 (ループ) を行う場合には、for キーワードを使って繰り返し処理を記述します。
他のプログラミング言語を知っている方は、while, do-while, for-each などのループにも馴染みがあるかと思いますが、 Go では for だけで繰り返し処理をおこないます。
Go の for ループ
Go の for ループで決まった回数繰り返す
まずは基本的な for ループの書き方を説明します。
for キーワードに続いて、繰り返し処理の回数を数える変数を宣言して初期化します。通常、繰り返し回数を数える目的に用意した変数を「カウンター」などと呼びます。
セミコロン ; に続いて、次のセクションには「繰り返し条件」を記述します。「繰り返し条件」が真 (true) である間、ループが繰り返されます。
さらにセミコロン ; に続いて、「ループ一回毎に一回処理するセクション」があり、そこでカウンターを操作します。
カウンターは通常は i++ などとして、インクリメント (+1) します。しかし、 i += 2 などとして、2 ずつ増やしても構いません。
この場所では必ずしも、カウンターを操作しないといけないわけではありませんが、通常はそのようにします。
具体例をみてみましょう。
次の例ではカウンターとして変数 i を用意して、5回の繰り返し処理を行っています。
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
}
実行結果は次のようになります。
go run main.go
0
1
2
3
4
カウンター i は、一度ループするたびに i++ で 1 ずつ増えてゆき、 i が 5 となったところで、 i < 5 という条件が false になるので、そこでループが終了します。
Go の繰り返し条件のみの for ループ
上の書き方では for に続いてカウンターを初期化し、 for に並ぶ箇所でカウンターの操作を行いました。
この書き方のほか、次のように繰り返し条件のみを記述する書き方もあります。
for 繰り返し条件 {
// 繰り返し
}
他の言語でしばしば while ループとして記述する状況に相当します。
具体的には次のようにします。
c := 0
for c < 5 {
fmt.Println(c)
c += 2
}
// 実行結果
// 0
// 2
// 4
Go のループの break
for ループは break 文で中断することができます。
次の例では i が 2 になったところで、for ループは終了します。
for i := 0; i < 5; i++ {
if i == 2 {
break // break で for ループを抜ける
}
fmt.Println(i)
}
ちなみに、次のように for ループがネスト (入れ子) になっている場合、内側のループで break 文を実行すると、基本的に内側のループが中断します。
fmt.Println("i j")
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if j == 1 {
break
}
fmt.Println(i, j)
}
}
// 実行結果
// i j
// 0 0
// 1 0
// 2 0
内側の for ループ内での break で外側のループを中断したい場合は、外側のループにラベルを設定して、 break ラベル とします。
fmt.Println("i j")
outer: //外側のループに設定したラベル
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if j == 1 {
break outer // ラベルを指定して break
}
fmt.Println(i, j)
}
}
// 実行結果
// i j
// 0 0
Go のループの continue
for ループは continue 文を使うと、繰り返し処理のその回をそこで中断して次のループを継続します。
次の例では i の剰余 (i%2) が 1 となるときは、 continue 文で処理を中断して i の値を出力せずに、次の繰り返し単位を続行します。
for i := 0; i < 5; i++ {
if i%2 == 1 {
continue
}
fmt.Println(i)
}
go run main.go
0
2
4
Go の繰り返し回数の決まっていない for ループ
Go の for ループでは、次の書き方もあります。
for {
// 繰り返し
}
この場合、任意のタイミングで break 文を実行することでループを抜けます。
このようなループは、なんらかの処理を、成功するまで実行して成功したら処理を抜ける、というようなリトライ処理などで使えます。
ただし、break 文を実行する条件が正しく設定されていないと無限ループに陥ってしまい、いつまでも処理が終了しないなどの問題を引き起こすことになります。
ループの終了条件には十分注意が必要です。
Go の for range ループ
Go の配列 (スライス) の要素毎の for-range ループ
Go の配列やスライスなどでは、連続した要素リストのインデックスと値を順番に受け取り、ループ処理をすることができます。
この場合、for-range を使って次のようにします。
for インデックスの変数, 値の変数 := range 配列またはスライス {
// 繰返し処理
}
次の例では変数 i にインデックスが、 v に値がセットされます。
s := []int{10, 20, 30, 40, 50}
for i, v := range s {
fmt.Println(i, v)
}
// 実行結果
// 0 10
// 1 20
// 2 30
// 3 40
// 4 50
不要な変数はアンダースコア _ を書くことで、省略できます。
for _, v := range s {
// ...
}
Go のマップ要素の for-range ループ
マップ (map)でも、配列やスライスの場合と同様に for-range が利用できます。
package main
import "fmt"
func main() {
stocks := map[string]float64{
"MSFT": 245.71,
"AAPL": 123.74,
"GOOGL": 2347.58,
}
for n, v := range stocks {
fmt.Println(n, v)
}
}
go run main.go
MSFT 245.71
AAPL 123.74
GOOGL 2347.58
尚、map のイテレーションではキー・値の出現順序が決まっていないことに注意が必要です。
上記のコード何度か繰返し実行していると、次のようにも表示される場合があることに気付くと思います。
AAPL 123.74 // 先頭に AAPL が表示されている
GOOGL 2347.58
MSFT 245.71
従って、map で for-range ループを使用する場合は、順序に依存したコードを書かないように注意を払う必要があります。