Rustの基礎 - 反復処理(while文)

提供: MochiuWiki : SUSE, EC, PCB

概要

Rustにおいて、条件が成立する時に反復処理 (イテレーション) をするwhile文を記載する。


while文の反復処理

whileの後ろに条件式を記述して、波括弧{}でブロックを囲む。
条件式は括弧()で囲む必要はないが、条件式は必ずbool型でなければならない。

 while 条件式 {
    実行コード
 }


以下の例では、while文の無限ループを記述している。

実行した場合は延々と"無限に処理を繰り返す。"メッセージが繰り返し表示される。
無限ループを止めたい場合は、[Ctrl]キー + [C]キーを同時押下して終了させる。

 fn main() {
    while true {
       println!("無限に処理を繰り返す。");
    }
 }


※注意
無限ループを記述する場合は、while trueよりもloop文を使用することが推奨される。
loop文は、明示的に無限ループを表現するRust特有の構文である。

 fn main() {
    loop {
       println!("無限に処理を繰り返す。");
    }
 }


while文を使用した一般的な反復処理として、以下に示すような記述方法がある。

 fn main() {
    let mut count = 0;
    while count < 10 {
       println!("{}", count);
       count += 1;
    }
 }
 
 // 出力
 0
 1
 2
 3
 4
 5
 6
 7
 8
 9



break文で反復処理を中止する

何かの条件によって途中で反復処理を中止したい場合がある。
この時、break文を使用すると反復処理を中止して処理を抜けることができる。

以下の例では、変数countが5を超えた場合 (変数countが6になった場合)、while文を抜ける。

 fn main() {
    let mut count = 0;
    while count < 10 {
       if count > 5 {
          break;
       }
       println!("カウントは{}です。", count);
       count += 1;
    }
 }
 
 // 出力
 カウントは0です。
 カウントは1です。
 カウントは2です。
 カウントは3です。
 カウントは4です。
 カウントは5です。


loop文でbreak文を使用する場合は、値を返すことができる。
これは、loop文が式として機能するためである。

 fn main() {
    let mut count = 0;
    let result = loop {
       count += 1;
       if count == 10 {
          break count * 2;
       }
    };
    println!("結果は{}です。", result);
 }
 
 // 出力
 結果は20です。



continue文で次の反復処理を行う

continue文を使用すると、特定の処理だけ行わずに再び反復処理を行うことができる。

 fn main() {
    let mut count = 0;
    while count < 10 {
       if count > 5 {
          break;
       }
       if count == 3 {
          count += 1;
          continue;
       }
       println!("カウントは{}です。", count);
       count += 1;
    }
 }
 
 // 出力
 カウントは0です。
 カウントは1です。
 カウントは2です。
 カウントは4です。
 カウントは5です。


loop文でcontinue文を使用する場合も同様である。

 fn main() {
    let mut count = 0;
    loop {
       count += 1;
       if count > 10 {
          break;
       }
       if count % 2 == 0 {
          continue;
       }
       println!("カウントは{}です。", count);
    }
 }
 
 // 出力
 カウントは1です。
 カウントは3です。
 カウントは5です。
 カウントは7です。
 カウントは9です。



ラベル付きループによる制御

ラベルを使用して入れ子になったループを制御することができる。
ラベルは、シングルクォート ' で始まる識別子である。

以下の例では、外側のループにラベル'outerを付けて、内側のループから外側のループを抜ける。

 fn main() {
    let mut count = 0;
    'outer: loop {
       println!("外側のループ: count = {}", count);
       let mut inner_count = 0;
       loop {
          println!("  内側のループ: inner_count = {}", inner_count);
          if inner_count >= 2 {
             break;
          }
 
          if count >= 2 {
             break 'outer;
          }
 
          inner_count += 1;
       }
       count += 1;
    }
    println!("ループを抜けました。");
 }
 
 // 出力
 外側のループ: count = 0
   内側のループ: inner_count = 0
   内側のループ: inner_count = 1
   内側のループ: inner_count = 2
 外側のループ: count = 1
   内側のループ: inner_count = 0
   内側のループ: inner_count = 1
   内側のループ: inner_count = 2
 外側のループ: count = 2
   内側のループ: inner_count = 0
 ループを抜けました。


ラベル付きcontinue文を使用して、外側のループの次の反復に進むこともできる。

 fn main() {
    let mut count = 0;
    'outer: while count < 5 {
       println!("外側のループ: count = {}", count);
       let mut inner_count = 0;
       while inner_count < 5 {
          println!("  内側のループ: inner_count = {}", inner_count);
          if inner_count == 2 {
             count += 1;
             continue 'outer;
          }
          inner_count += 1;
       }
       count += 1;
    }
 }
 
 // 出力
 外側のループ: count = 0
   内側のループ: inner_count = 0
   内側のループ: inner_count = 1
   内側のループ: inner_count = 2
 外側のループ: count = 1
   内側のループ: inner_count = 0
   内側のループ: inner_count = 1
   内側のループ: inner_count = 2
 外側のループ: count = 2
   内側のループ: inner_count = 0
   内側のループ: inner_count = 1
   内側のループ: inner_count = 2
 外側のループ: count = 3
   内側のループ: inner_count = 0
   内側のループ: inner_count = 1
   内側のループ: inner_count = 2
 外側のループ: count = 4
   内側のループ: inner_count = 0
   内側のループ: inner_count = 1
   内側のループ: inner_count = 2



Rustにはwhile-else構文はない

Rustにはwhile-else構文は存在しない。
代わりに、フラグ変数や関数の戻り値を使用して同様の処理を実現することができる。

以下の例では、フラグ変数を使用して、break文で抜けたかどうかを判定している。

 fn main() {
    let mut count = 0;
    let mut completed = true;
 
    while count < 10 {
       if count > 5 {
          completed = false;
          break;
       }
       println!("カウントは{}です。", count);
       count += 1;
    }
 
    if completed {
       println!("反復処理は正常に完了しました。");
    }
 }
 
 // 出力
 カウントは0です。
 カウントは1です。
 カウントは2です。
 カウントは3です。
 カウントは4です。
 カウントは5です。


次に、break文なしで正常に完了する場合の例を示す。

 fn main() {
    let mut count = 0;
    let mut completed = true;
 
    while count < 10 {
       println!("カウントは{}です。", count);
       count += 1;
    }
 
    if completed {
       println!("反復処理は正常に完了しました。");
    }
 }
 
 // 出力
 カウントは0です。
 カウントは1です。
 カウントは2です。
 カウントは3です。
 カウントは4です。
 カウントは5です。
 カウントは6です。
 カウントは7です。
 カウントは8です。
 カウントは9です。
 反復処理は正常に完了しました。


実用的な例として、検索処理でキーワードが見つかった場合はbreak文を実行し、見つからなかった場合は処理を行う。

 fn main() {
    let items = vec!["apple", "banana", "orange", "grape"];
    let search_key = "melon";
    let mut found = false;
    let mut index = 0;
 
    while index < items.len() {
       if items[index] == search_key {
          found = true;
          break;
       }
       index += 1;
    }
 
    if found {
       println!("{}が見つかりました。", search_key);
    }
    else {
       println!("{}は見つかりませんでした。", search_key);
    }
 }
 
 // 出力
 melonは見つかりませんでした



while letによるパターンマッチ

Rustには、while let構文があり、Option型やResult型などのパターンマッチを行いながらループすることができる。
これは、値が Some である限り反復処理を続ける場合に便利である。

 fn main() {
    let mut stack = vec![1, 2, 3, 4, 5];
 
    while let Some(top) = stack.pop() {
       println!("{}", top);
    }
 }
 
 // 出力
 5
 4
 3
 2
 1


これは、以下に示すようなmatch式を使用したコードと同等である。

 fn main() {
    let mut stack = vec![1, 2, 3, 4, 5];
 
    loop {
       match stack.pop() {
          Some(top) => println!("{}", top),
          None => break,
       }
    }
 }
 
 // 出力
 5
 4
 3
 2
 1