Go 言語入門基礎学習ノートの Go 言語のループ文
ループ文#
for ループ#
Go 言語の For ループには 3 つの形式があり、そのうちの 1 つだけがセミコロンを使用します。
- C 言語の
for
と同様:
for init; condition; post { }
init
: 一般に代入式で、制御変数に初期値を与えます;condition
: 関係式または論理式で、ループ制御条件;post
: 一般に代入式で、制御変数の増分または減分。
init と post のパラメータはオプションであり、直接省略することができます。これは While 文に似ています。
- C の
while
と同様:
for condition { }
- C の
for(;;)
と同様:
// 無限ループ
for { }
// または
for true { }
for ループの range 構文は、スライス、マップ、配列、文字列などを反復ループすることができます。
for key, value := range oldMap {
newMap[key] = value
}
上記のコードの key と value は省略可能です。
もし key のみを読み取りたい場合、形式は次のようになります:
for key := range oldMap
// または
for key, _ := range oldMap
もし value のみを読み取りたい場合、形式は次のようになります:
for _, value := range oldMap
Go 言語ではすべての宣言された変数は使用されなければならないため、_
を代わりに使用することができます。
ループ制御文#
制御文 | 説明 |
---|---|
break 文 | 現在の for ループを中断したり、switch 文を抜けるためによく使用されます |
continue 文 | 現在のループの残りの文をスキップし、次のループを続行します。 |
goto 文 | 制御をラベルの付けられた文に移動します。 |
break 文#
Go 言語では、break 文は現在のループまたは switch 文の実行を終了し、そのループまたは switch 文のコードブロックを抜けるために使用されます。
break 文は以下のいくつかの側面で使用できます:
- ループ文の中でループを抜け、ループの後の文を実行します。
- switch 文の中で、1 つの case を実行した後に文を抜ける役割を果たします。
- select 文の中でも break を適用でき、select 文を抜けて実行を続けません。
- 多重ループの中では、ラベルを使用して抜けたいループを指定できます。
多重ループでのラベルを使用する場合と使用しない場合の違い:
package main
import "fmt"
func main() {
// ラベルを使用しない
fmt.Println("---- break ----")
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break
}
}
// ラベルを使用する
fmt.Println("---- break label ----")
re:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break re
}
}
}
// 出力結果
---- break ----
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
---- break label ----
i: 1
i2: 11
このように、ラベルを使用しない break は現在のループのみを抜けることができます。一方、ラベルを使用する break は抜けるループを指定できます。
Go 言語では、break 文の select 文での使用は比較的特殊です。select 文の特性により、場合によっては break 文を直接使用して select 文自体を抜けることができません。なぜなら、select 文は非ブロッキングであり、すべての通信操作が準備が整うのを待ち続けるからです。
以下の例のように、select が無限ループ文の中にネストされているため、break 文は select 文を抜けるだけで、外側の for ループを抜けることはありません。外側の for ループを抜けたい場合は、break + ラベルを使用して実現できます。それ以外にも return や goto 文を使用することもできます。
同様の状況のswitch 文でも、これらの 3 つの方法を使用できます。
package main
import (
"fmt"
"time"
)
func process(ch chan int) {
Loop:
for {
select {
case val := <-ch:
fmt.Println("受信した値:", val)
// いくつかのロジックを実行
if val == 5 {
break Loop
// または return を使用して現在の関数の実行を早期終了
// goto EndLoop を使用して関数の最後の行にジャンプすることもできます
}
default:
fmt.Println("まだ値は受信されていません。")
time.Sleep(500 * time.Millisecond)
}
}
EndLoop:
}
func main() {
ch := make(chan int)
go process(ch)
time.Sleep(2 * time.Second)
ch <- 1
time.Sleep(1 * time.Second)
ch <- 3
time.Sleep(1 * time.Second)
ch <- 5
time.Sleep(1 * time.Second)
ch <- 7
time.Sleep(2 * time.Second)
}
// 出力結果
まだ値は受信されていません。
まだ値は受信されていません。
受信した値: 1
まだ値は受信されていません。
受信した値: 3
まだ値は受信されていません。
受信した値: 5
continue 文#
Go 言語の continue 文は break 文に似ています。しかし、continue はループを抜けるのではなく、現在のループをスキップして次のループ文を実行します。
多重ループの中では、ラベルを使用して抜けたいループを指定できます。
多重ループでのラベルを使用する場合と使用しない場合の違い:
package main
import "fmt"
func main() {
// ラベルを使用しない
fmt.Println("---- continue ---- ")
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue
}
}
// ラベルを使用する
fmt.Println("---- continue label ----")
re:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue re
}
}
}
// 出力結果
---- continue ----
i: 1
i2: 11
i2: 12
i2: 13
i: 2
i2: 11
i2: 12
i2: 13
i: 3
i2: 11
i2: 12
i2: 13
---- continue label ----
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
goto 文#
Go 言語の goto 文は無条件に指定された行に移動することができます。
goto 文は通常、条件文と組み合わせて使用されます。条件移動、ループの構成、ループ体からの脱出などの機能を実現できます。
ただし、構造化プログラミング設計では一般的にgoto 文の使用は推奨されません。プログラムのフローが混乱し、理解やデバッグが困難になる可能性があるためです。
package main
import "fmt"
func main() {
/* ローカル変数を定義 */
var a int = 10
/* ループ */
LOOP: for a < 20 {
if a == 15 {
/* イテレーションをスキップ */
a = a + 1
goto LOOP
}
fmt.Printf("aの値は : %d\n", a)
a++
}
}
// 出力結果
aの値は : 10
aの値は : 11
aの値は : 12
aの値は : 13
aの値は : 14
aの値は : 16
aの値は : 17
aの値は : 18
aの値は : 19