ラベル付きのfor breakで確実ループを抜けるGoプログラム

Go言語
この記事は約7分で読めます。
Go初学者
Go初学者

Goのラベル付きのfor breakの動きを知りたいな。

この記事ではラベル付きfor breakについて理解できます!
  • どんな場面でラベル付きfor breakを使用するのかプログラムで確認

今回はラベル付きの for breakについてお伝えしていきます。

頻繁に使用する構文ではありませんが、Go言語の機能のひとつとして押さえておきましょう。

もりぴ
この記事を書いた人

XHTML1.0時代にHTML&CSSを勉強した経験あり。無趣味だった私が2020年5月からプログラミング学習を開始し現在も挫折せずに趣味で学習を楽しんでいる51歳。プログラミングの楽しさをブログを通してお伝えしていきます。

もりぴをフォローする

ラベル付きfor breakとは?

ラベル付きの for break は同一コードで何回も重ねられた(ネスト)for文で、抜け出す機能です。

ネストされたfor文から break を使っても抜け出さるのは、break を使用しているfor文のみです。

Go初学者
Go初学者

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

もりぴ
もりぴ

ごめんなさい…プログラムで確認していきましょう。

ラベル付き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
スタート!
終わり
Go初学者
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.Ticktime.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!
ここまで実行してください!
Go初学者
Go初学者

おっ!最後までプログラムが実行されましたね!

return ではプログラムが終了してしまいますが、ラベル付きの for break を使用するとfor文から抜け出すので、最後の fmt.Println("ここまで実行してください!") まで実行されるのです。

このような使い方もできます。

【最後に】ラベル付きfor breakについて

今回はラベル付きの for break を紹介いたしました。

最初のfor文がネストされたプログラムは活用されることが無いですがラベル付きの for break の動きがもっともわかりやすい例としてあげてみました。

Go言語の機能として用意されているということを覚えておけば、いつか役立つかもしれません。

もりぴ
もりぴ

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

comment

タイトルとURLをコピーしました