
Goのラベル付きのfor breakの動きを知りたいな。
今回はラベル付きの for
break
についてお伝えしていきます。
頻繁に使用する構文ではありませんが、Go言語の機能のひとつとして押さえておきましょう。
ラベル付きfor breakとは?
ラベル付きの for
break
は同一コードで何回も重ねられた(ネスト)for文で、抜け出す機能です。
ネストされたfor文から break
を使っても抜け出さるのは、break
を使用しているfor文のみです。

わかりずらい説明ですね…

ごめんなさい…プログラムで確認していきましょう。
ラベル付きfor breakをプログラムで確認
まずは、下記のプログラムを実行してみましょう。
package main
import "fmt"
func main() {
// この例だと無限ループする
for {
for {
for {
fmt.Println("スタート!")
break
}
fmt.Println("処理しないで!無視して!!")
}
fmt.Println("処理しないで!無視して!!")
}
fmt.Println("終わり")
}
// 出力結果は無限ループ
$ go run main.go
スタート!
処理しないで!無視して!!
スタート!
処理しないで!無視して!!
スタート!
処理しないで!無視して!!

無限ループを抜けだすのは ctrl + c の同時押しです。
このプログラムだと、break
しているfor文のみから抜け出すことはできますが、残り2つのfor文からは抜け出せずに無限ループになります。
無限ループを回避するためにラベル付きの for
break
を使用します。
package main
import "fmt"
func main() {
// ラベル付きfor文を使用する場合
// breakしたら一気にfor文を抜ける
// この例だと「Loop」というラベルを付けて抜ける
Loop: // ラベル名は何でも良い
for {
for {
for {
fmt.Println("スタート!")
break Loop // breakの後にラベルを記述
}
fmt.Println("処理しないで!無視して!!")
}
fmt.Println("処理しないで!無視して!!")
}
fmt.Println("終わり")
}
// 出力結果
$ go run main.go
スタート!
終わり

おっ!無限ループから抜け出しましたね。
抜けたいfor文の前にラベルを付けます。
今回は Loop:
としましたが、ラベル名は任意の名称で大丈夫です。
break
のあとに任意のラベル名を記述することで、for文から抜け出すことができます。
ただ、このようなプログラムは存在するか定かではないので、ちょっと実用的なプログラム例をお見せしましょう。
for文とselect文でのラベル付きfor break
ここでは A Tour of GoのDefault Selection で紹介されている select文 のプログラムを例にしてお伝えしていきます。
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
}
// 出力結果
$ go run main.go
.
.
.
tick.
.
.
tick.
.
tick.
.
.
tick.
.
.
BOOM!
上記のような出力結果となります。
ここで使用されているtimeパッケージの time.Tick
と time.After
について説明いたします。
time.Tick | 指定した時間に処理を繰り返す |
time.After | 指定した時間より後に処理をする |
50ミリ秒ごとに .
が出力され、100ミリ秒ごとに time.Tick
が実行され tick
が出力、最後に500ミリ秒後に BOOM!
が出力され return
でプログラムが終了されます。
それでは、下記のようなプログラムで最後までプログラムは終了すると思いますか?
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
fmt.Println("ここまで実行してください!") //ここを追記
}
このプログラムでは return
でプログラムが終了されるので fmt.Println("ここまで実行してください!")
まで処理が終了しません。
ここで return
の代わりにラベル付きの for
break
を使用してみましょう。
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
Loop: // ラベルを追記
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
// return は使用しない
break Loop // ラベル付きbreakを記述
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
fmt.Println("ここまで実行してください!")
}
// 出力結果
$ go run main.go
.
.
.
tick.
.
.
tick.
.
tick.
.
.
tick.
.
.
BOOM!
ここまで実行してください!

おっ!最後までプログラムが実行されましたね!
return
ではプログラムが終了してしまいますが、ラベル付きの for
break
を使用するとfor文から抜け出すので、最後の fmt.Println("ここまで実行してください!")
まで実行されるのです。
このような使い方もできます。
【最後に】ラベル付きfor breakについて
今回はラベル付きの for
break
を紹介いたしました。
最初のfor文がネストされたプログラムは活用されることが無いですがラベル付きの for
break
の動きがもっともわかりやすい例としてあげてみました。
Go言語の機能として用意されているということを覚えておけば、いつか役立つかもしれません。

参考知識程度で良いと思いますよ。
comment