Menu

Go言語のwhile文:whileとdo-whileの書き方

Goにwhileキーワードはありません。条件だけを書いたforループがGoのwhileループで、条件のないforは無限ループ、do-whileは最後にチェックを置いた無限ループです。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

Goに while キーワードはありません。for の後に条件を書けば、それがwhileループです。

条件は毎回の反復の前にチェックされるので、最初から偽なら本体は一度も実行されません。C、Java、JavaScriptの while (balance < 2000) から、かっことキーワードを除いたものとまったく同じです。Goの設計者は、あらゆる形のループに1つのキーワードを選びました。4つの形はすべてforループのページで紹介しています。

while(true):無限ループ

条件をまるごと省くと、中の何かが終わらせるまでループが続きます。

Goらしい書き方は for { } です。for true { } もコンパイルできますが、書いた人が他の言語から来たように読めます。

無限ループを終わらせるものは4つあります。break(ループを抜ける)、return(関数を抜ける)、panic、そして os.Exit です。main がこれらのない for {} にとどまっているプログラムは、強制終了されるまで動き続けます。サーバーやワーカーにはまさにそれが正しい挙動です。

do-while

do-whileは、条件をチェックする前に本体を1回実行します。Goに専用の構文はありません。無限ループの最後にチェックを置きます。

本体は何があっても少なくとも1回実行されます。これがdo-whileを特徴づける性質です。乱数源は固定のシードを使っているので、実行するたびに同じ出力になります。本当にランダムにするには、シードを与えた乱数源を使わずに rand.IntN を使います。

2つ目の形として、最初の1回を強制してヘッダーに条件を残す方法もあります。

for first := true; first || condition(); first = false {
	// body
}

これでも動きますが、最後に break を置いた無限ループのほうが読みやすく、ほとんどのGoのコードもそちらを使っています。

終わるまで読み取る

実際のGoのコードで最もよく見るwhileループは、入力がなくなるまで読み取るものです。bufio.Scanner はそのために設計されています。Scan は入力の終わりかエラーで false を返すので、そのままループの条件になります。

strings.NewReader(input)os.Stdin に置き換えれば、同じループでユーザーの入力を1行ずつ読めます。ループの後で scanner.Err() をチェックしてください。Scanfalse を返しただけでは、入力が正常に終わったのか失敗したのかわかりません。

breakとcontinue

どちらも for のすべての形で使えます。

条件だけのループでは、continue はそのまま条件に飛びます。そのため、気づきにくいバグを作りやすくなります。カウンタを本体の 最後 で更新していると、それより上の continue が更新を飛ばし、ループが終わらなくなります。上の例のようにカウンタを先頭で更新するか、continue の後でもpost文が実行される3つの節の for を使います。

何かを待つ

条件を待つループは、空回りするのではなく、ブロックするかスリープするべきです。

// Wrong: burns a CPU core while waiting
for !ready {
}

// Better: poll with a delay
for !isReady() {
	time.Sleep(100 * time.Millisecond)
}

別のゴルーチンが書き込む普通の変数をポーリングするのは、データ競合でもあります。ゴルーチン間では、代わりにチャネル、sync.WaitGroupsync.Cond で待つか、タイマー付きの select を使います。上限のあるリトライのループには、永遠に回ることがないように回数を数える for を使いましょう。

for attempt := 1; attempt <= 5; attempt++ {
	if err := connect(); err == nil {
		break
	}
	time.Sleep(time.Duration(attempt) * 200 * time.Millisecond)
}

よくある間違い

  • 条件の変数を変え忘れる。 for i < 10 { fmt.Println(i) } は終わりません。どのwhileループにも、本体の中に出口へ近づける何かが必要です。
  • while と書く。 while x < 5 {}syntax error: unexpected name x at end of statement になります。while はキーワードではないので、コンパイラは普通の名前として読みます。
  • 習慣でかっこを付ける。 for (x < 5) {} はコンパイルでき、gofmt がかっこを取り除きます。
  • ループの中で変数を宣言する。 for n := 10; n > 0 {} は構文エラーです。初期化節のあるループには3つの節すべてが必要です。ループの前で n を宣言するか、3つの節の完全な形で書きます。

よくある質問

Goにwhileループはありますか?

キーワードとしてはありません。Goはすべてのループに for を使い、条件だけを書いた for がまさにwhileループです。

for count < 10 {
	count++
}

CやJavaの while (count < 10) と同じく、条件は毎回の反復の前にチェックされます。

Goでwhile(true)はどう書きますか?

後ろに何も書かずに for とします:for { ... }breakreturn、panic、os.Exit のいずれかで終わるまでループします。for true { ... } もコンパイルできますが、Goらしい書き方は for { } です。

Goでdo-whileループはどう書きますか?

無限ループを使い、条件のチェックを本体の最後に置きます。

for {
	// body runs at least once
	if !condition {
		break
	}
}

本体は条件がテストされる前に必ず1回実行されます。これがdo-whileの意味です。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める