今川館

都内勤務の地味OLです

ラベル付きbreak, continue, goto

Goのプログラムを見ていて、何年ぶりか分からないくらい久しぶりにラベル付きbreakを見かけた。

Goプログラミング言語仕様 - golang.jp

ラベル付きステートメント

ラベル付きステートメントは、goto、break、continueステートメントの宛先となります。

この通り、break, continueの他に、gotoにも使えるらしい。(つまりgoto文をGoは許している)

試してみた

ラベルは自分がいるスコープの外に定義されているものしか参照できない模様。
試しに以下のサンプルコードを書いて動かしてみた。

package main

import (
	"fmt"
	"time"
)

func main() {
L:
	for i := 1; true; i++ {

		for j := 1; true; j++ {

			fmt.Printf("i=%v> j=%v\n", i, j)

			if i == 2 && j == 2 {
				continue L
			}

			if i%2 != 0 && j == 3 {
				goto L2
			}
			if j == 3 {
				break L
			}

			time.Sleep(200 * time.Millisecond)
		}

	L2:
	}
}

自分でも挙動が読めない中、試行錯誤した結果、上記プログラムを動かすと以下の出力が得られる。

出力内容

i=1> j=1
i=1> j=2
i=1> j=3 // ここで goto L2 の条件にマッチしてjのループを抜ける
i=2> j=1
i=2> j=2 // ここで continue L の条件にマッチしてjのループを抜ける
i=3> j=1
i=3> j=2
i=3> j=3
i=4> j=1
i=4> j=2
i=4> j=3 // ここで break L の条件にマッチしてiのループを抜ける

当然これはやっておくでしょう

goto出てきたら当然コレはやっとくでしょう。

package main

import (
	"fmt"
	"strings"
	"time"
)

var ora = []string{
	"ハァ テレビもねぇ! ラジオもねぇ!",
	"クルマもそれほど走ってねぇ!",
	"ピアノもねぇ! バーもねぇ! おまわり毎日ぐーるぐる!",
}

const delay = time.Duration(750 * time.Millisecond)

func Sing(message string) {
	xs := strings.Split(message, " ")
	length := len(xs)
	for i, x := range xs {
		fmt.Print(x)
		if i+1 < length {
			fmt.Print(" ")
			time.Sleep(delay)
		}
	}
	time.Sleep(delay)
	fmt.Println()
}

func main() {

	for i := 0; true; i++ {

		Sing(ora[i])

		if i >= 2 {
			Sing("おらこんな村いやだぁ〜 おらこんな村いやだぁ〜")
			Sing("東京へ出るだぁ〜〜〜")
			goto Tokyo
		}
	}

Tokyo:

	for i := 0; true; i++ {
		Sing("東京へ出だな〜ら 銭コア貯めでぇ 東京でベコ飼うだぇ〜〜")
		break Tokyo
	}
}

最終的にここまで調整しました。