Rustのloop
Rustには、コードをくり返す方法が3つあります。loop、while、for です。このページでは、その中でいちばんシンプルでストレートな loop を扱います。loop は、止めるように指示するまでずっとくり返し続けます。
基本的なloop
Section titled “基本的なloop”fn main() { let mut count = 0;
loop { count += 1; println!("{count}");
if count == 3 { break; } }}実行結果:
123loop はそれだけでは決して止まりません。ループを終わらせるのは break です。if count == 3 { break; } がなければ、このプログラムは永遠に数字を表示し続けます。
ループから値を返す
Section titled “ループから値を返す”while や for にはできなくて、loop にはできることがあります。break の後ろに値を書くと、それがループ全体の結果になるのです。
fn main() { let mut count = 0;
let result = loop { count += 1; if count == 10 { break count * 2; // ループを止めて、値を返す } };
println!("{result}");}実行結果:
20これは「うまくいくまで再試行して、うまくいったら結果を受け取る」といった場面で便利です。実際のコードでも、思っている以上によく見かける書き方です。
ループの閉じカッコ } の後ろにセミコロンがあることに注目してください。loop { ... } 全体が let result = ...; の右辺なので、let x = 5; と同じように、let 文の最後には ; が必要です。
while true ではなく loop を使うのはなぜ?
Section titled “while true ではなく loop を使うのはなぜ?”ほかの言語から来た人は、無限ループを while true { ... } と書くかもしれません。Rustでもこれは動きますが、コンパイラが警告を出します。
warning: denote infinite loops with `loop { ... }` --> src/main.rs:5:5 |5 | while true { | ^^^^^^^^^^ help: use `loop`「無限ループは loop { ... } で書きましょう」という意味の警告です。これは単なる書き方の好みの話ではありません。Rustは、loop の本体は必ず実行されること、そして抜け出す方法は break しかないことを知っています。一方、while true についてはそう判断しません。条件の値までは見ないからです。この違いは、ループの中で変数に値を入れるときに、はっきり表れます。
fn main() { let mut n = 1; let answer; // まだ値がない
loop { if n * n > 50 { answer = n * n; // 抜ける直前に値を入れる break; } n += 1; }
println!("50を超える最初の平方数は{answer}です");}実行結果:
50を超える最初の平方数は64ですloop なら、println! にたどり着く道はその break しかないとRustにはわかるので、answer には必ず値が入っています。loop を while true に変えると、error[E0381]: used binding answer is possibly-uninitialized(「answer は初期化されていない可能性がある」)というエラーになります。コンパイラは、if を一度も実行しないままループが終わるかもしれないと考えるのです。
実際には、このプログラムをいちばんすっきり書くなら、上で見た「値を返す break」を使います。let answer = loop { ... break n * n; ... }; のようにです。どちらにしても教訓は同じで、「break するまでずっと」という意味なら loop と書きましょう。
loopを使う場面
Section titled “loopを使う場面”何回くり返すかが前もってわからないときは、loop がぴったりです。範囲やリストを順に数えていくのではなく、ある条件が成り立つのを待っている場合ですね。数を数えたり、コレクションを順に処理したりするなら、次に紹介する while や for のほうがたいてい読みやすくなります。
1. 発射のカウントダウン
Section titled “1. 発射のカウントダウン”loop を使って5から1までカウントダウンを表示し、最後に 発射! と表示してください。ヒント:let mut n = 5; から始めて、n が0になったら break します。
解答を見る
fn main() { let mut n = 5;
loop { if n == 0 { break; } println!("{n}..."); n -= 1; }
println!("発射!");}実行結果:
5...4...3...2...1...発射!チェックが先にあるので、n が0になると 0... を表示する前にループが止まります。
2. 1000を超える最初の2のべき乗
Section titled “2. 1000を超える最初の2のべき乗”1から始めて、2倍にし続けます。値を返す break を使って1000を超える最初の数を求め、何回2倍にしたかも数えてください。ヒント:ループの外に mut のカウンタを用意して、let power = loop { ... }; と書きます。
解答を見る
fn main() { let mut value = 1; let mut doublings = 0;
let power = loop { value *= 2; doublings += 1; if value > 1000 { break value; } };
println!("{doublings}回2倍にして{power}");}実行結果:
10回2倍にして1024break value; はループを終わらせて、value を power に渡します。カウンタはループの外にあるので、ループが終わった後も値が残っています。
loopはbreakで止めるまでずっとくり返します。抜け出すbreakを必ず用意しましょう。break 値;はループを止めると同時に、値をループ式全体の結果として返します。while trueではなくloopと書きましょう。loopの本体は必ず実行されるとRustが知っているので、変数のチェックに役立ちます。- 決まった回数を数えるときではなく、「ある条件が起きるまで」くり返したいときに
loopを使いましょう。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. 何も付けない loop が永遠に回り続けるのを止めるのは何ですか?
2. ループの中で break count * 2; と書くと、どうなりますか?
3. このページによると、while や for より loop を選ぶべきなのはどんなときですか?
4. Rustで while true { ... } と書くと、どうなりますか?
スコア: 0 / 4
さらに詳しく
Section titled “さらに詳しく”- ループでの繰り返し — The Rust Programming Language 日本語版:
loop、while、forを紹介する公式の入門です。 - ループから値を返す — The Rust Programming Language 日本語版:値を返す
breakについての短い節です。 - loop — Rust By Example 日本語版:
loop、break、continueの実行できるサンプルです。 - loopが返す値 — Rust By Example 日本語版:値を返すループの、もう1つの小さな例です。
- The
loopkeyword — 標準ライブラリのドキュメント(英語):loopとbreakがどう組み合わさって動くかを、簡潔にまとめたリファレンスです。