Rustのパターン付きループ: loopとwhile let
Rustのパターン付きループを徹底解説:値を返すloop式、データ消費に適したwhile let、ネストを脱出するループラベル。
Rustにおいてループは、単なる繰り返し処理を超えた表現力豊かな制御構造です。一般的な for や while に加え、値を直接返せる loop 式、パターンマッチングと連携してデータを消費する while let、そして多重ループを的確に制御するループラベルが備わっています。
10歳でもわかる説明:自動販売機とペッツ(キャンディ容器)#
2つのお菓子の仕組みをイメージしてください:
- 自動販売機 (
loopとbreak 値): 大当たりが出るまでコインを投入し続け、当たりが出た瞬間に景品が排出口から直接手元に戻ってきます(break 景品)。 - ペッツ容器 (
while let Some(キャンディ)): 首を後ろに倒すたびにキャンディがあるか確認します。キャンディが出てくる限り(Some(キャンディ))、食べ続けます。容器が空になった瞬間(None)、自然に食べるのをやめます。
graph TD
Start["ループ開始"] --> PatternMatch{"式がパターンにマッチするか?<br/>(例: Some(item))"}
PatternMatch -->|Yes: item を抽出| LoopBody["item を使ってループ本体を実行"]
LoopBody --> NextEval["次の要素 / 状態を評価"]
NextEval --> PatternMatch
PatternMatch -->|No: None / 不一致| Terminate["ループを正常終了"]
式としての loop: 値を返すループ#
C系言語の多くではループは文(statement)ですが、Rustの loop は式(expression)です。break の後ろに値を指定することで、ループから直接値を返すことができます:
src/main.rs
fn retry_operation() -> i32 {
let mut attempts = 0;
let result = loop {
attempts += 1;
if attempts == 3 {
// loop式から値 42 を直接 result 変数へ返す
break attempts * 14;
}
};
result
}
fn main() {
let output = retry_operation();
println!("処理結果: {output}"); // 42
}rustgraph LR
LStart["loop 開始"] --> Work["リトライ処理の実行"]
Work --> Check{"成功条件を満たしたか?"}
Check -->|No| Work
Check -->|Yes: break value| ReturnVal["result = 返された値"]
while let: パターンがマッチする間繰り返す#
スタックやキュー、チャネル、イテレータから順次要素を取り出す際、while let を使うことでスマートに記述できます:
冗長な書き方 (loop + match)#
src/main.rs
let mut stack = vec![1, 2, 3];
loop {
match stack.pop() {
Some(top) => println!("取り出した値: {top}"),
None => break, // 空になったら脱出
}
}rustwhile let による洗練された書き方#
src/main.rs
let mut stack = vec![1, 2, 3];
// stack.pop() が Some(top) を返す限り継続
while let Some(top) = stack.pop() {
println!("取り出した値: {top}");
}rust[!TIP] チャネル受信 (
receiver.recv()) やスタックの消費など、NoneやErrになるまで継続してデータを取り出す場面では常にwhile letを検討してください。
ループラベル: ネストした多重ループの制御#
入れ子になったループでは、通常の break や continue は最も内側のループにのみ適用されます。ループラベル(シングルクォート ' で始まる名前)を付けることで、外側のループを明示的に指定して脱出できます:
src/main.rs
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break; // 内側のループのみを脱出
}
if count == 2 {
break 'counting_up; // 外側の 'counting_up ループを脱出
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}rustsequenceDiagram
participant Outer as 外側ループ
participant Inner as 内側ループ
Outer->>Inner: 内側ループへ進入
Inner->>Inner: remaining == 9: break 内側
Inner-->>Outer: 外側ループに戻る
Outer->>Inner: 内側ループへ進入 count 2
Inner->>Outer: break counting_up: 外側ループから脱出
ループ構文の比較まとめ#
| 構文 | 主な用途 | break 値 対応 | パターンマッチング |
|---|---|---|---|
loop | 無限ループ、リトライ機構、ワーカースレッド | 対応 | 内部で match と併用 |
while 条件 | 一般的な真偽値(bool)条件による反復 | 非対応 | 非対応 |
while let パターン | Option や Result のシーケンス消費 | 非対応 | 対応(自動バインド) |
for 要素 in イテレータ | 既知のコレクションや範囲の走査 | 非対応 | 対応(要素の分配束縛) |
まとめ#
loopはbreak 値により計算結果を直接返すことができます。while letはシーケンスの取り出し処理において冗長なloop + matchを完全に解消します。- ループラベル(
'label: loop)により、複雑な多重ループのジャンプ先を正確に制御できます。