Rustのloopを初心者向けに徹底解説!基本構文から実践まで

2025年4月20日日曜日

Rust

プログラミングをしていると、「同じ処理を何度も繰り返したい!」という場面が出てきますよね。Rustにももちろん、繰り返し処理のための仕組みが用意されています。

その中でも、今回注目するのがRustのloopキーワードです!

他のプログラミング言語に触れたことがある方なら、「whileループ」や「forループ」はお馴染みかもしれません。Rustにも`while`や`for`は存在しますが、`loop`は少し独特な立ち位置にいます。

`loop`は、簡単に言うと「条件なしで永遠に処理を繰り返す」ためのループを作ります。「え、永遠に?止まらないの?」と不安になるかもしれませんが、ご心配なく!ちゃんとループを止める方法も用意されています。

`loop`の主な役割は以下の2つです。

  • 明示的に「無限ループ」を作りたい場合に使用する。
  • ループの中から`break`を使って特定の値を返すことができる(これは`loop`の面白い特徴!)。

まずは「こういうものがあるんだな」という感じで、気楽に読み進めてみてくださいね。

Rustのloopの基本的な書き方

`loop`の基本的な形はとてもシンプルです。以下のように書きます。

loop {
    // ここに繰り返したい処理を書く
}

`loop`というキーワードの後に、波括弧`{}`で囲まれたブロックが続きます。この波括弧の中に書かれた処理が、無限に繰り返されることになります。

試しに、簡単な例を見てみましょう。次のコードは、コンソールに「無限ループ中!」というメッセージを延々と表示し続けます。

fn main() {
    loop {
        println!("無限ループ中!");
    }
}

このコードを実行すると、ターミナルが「無限ループ中!」で埋め尽くされるはずです。(止めるには `Ctrl + C` を押してくださいね!)

このように、`loop`単体では止まる条件を持たない、というのが基本の動きになります。「じゃあ、どうやって止めるの?」という疑問が湧いてきますよね。次のセクションで、その方法を見ていきましょう!

Rustのloopの使い方

`loop`の基本がわかったところで、ここからはより実践的な使い方をサンプルコードと一緒に学んでいきましょう。無限ループを制御する`break`の使い方や、`loop`から値を返すテクニックなどを紹介します。

`break`でRustのloopを終了する

`loop`で作った無限ループから抜け出すには、`break`キーワードを使います。`break`は、ループ処理をその場で中断し、ループブロックの外に処理を移す命令です。

通常、`if`文と組み合わせて、「特定の条件が満たされたらループを終了する」という使い方をします。例を見てみましょう。カウンター変数が5になったらループを抜けるコードです。

fn main() {
    let mut counter = 0; // カウンター変数(変更するのでmutが必要)

    loop {
        println!("カウンター: {}", counter);
        counter += 1; // カウンターを1増やす

        if counter == 5 {
            println!("カウンターが5になったのでループを抜けます!");
            break; // ループを終了!
        }
    }

    println!("ループの外に出ました。");
}

実行結果

カウンター: 0
カウンター: 1
カウンター: 2
カウンター: 3
カウンター: 4
カウンターが5になったのでループを抜けます!
ループの外に出ました。

この例では、`loop`ブロックの中で毎回`counter`変数を1ずつ増やしています。

そして、`if counter == 5`の条件が真(true)になったときに`break`が実行され、ループが終了します。`break`がループを抜け出すための合言葉だと覚えておくと良いでしょう。

`break`でRustのloopから値を返す

Rustの`loop`には、他の多くの言語のループにはない面白い機能があります。それは、`loop`自体が「式」であり、`break`を使ってループから値を返すことができる点です!

「ループが値を返す?」と不思議に思うかもしれませんが、これは特定の条件を満たすまで何かを試行し、その結果を使いたい場合に役立ちます。

値を返すには、`break`の後に返したい値を続けます(例: `break 値;`)。そして、`loop`全体を`let`文などで変数に代入することで、返された値を受け取れます。

例として、カウンターが10になったら、そのカウンターの値の2倍をループの結果として返してみましょう。

fn main() {
    let mut counter = 0;

    let result = loop { // loop式の結果を変数resultで受け取る
        counter += 1;
        println!("試行中... カウンター: {}", counter);

        if counter == 10 {
            println!("カウンターが10になったので、結果を返します。");
            break counter * 2; // カウンターの2倍の値を返す!
        }
    }; // loop式の終わりにはセミコロンが必要な場合が多い

    println!("ループが返した値: {}", result); // => 20
}

実行結果:

試行中... カウンター: 1
試行中... カウンター: 2
試行中... カウンター: 3
試行中... カウンター: 4
試行中... カウンター: 5
試行中... カウンター: 6
試行中... カウンター: 7
試行中... カウンター: 8
試行中... カウンター: 9
試行中... カウンター: 10
カウンターが10になったので、結果を返します。
ループが返した値: 20

`if counter == 10`の条件が満たされたとき、`break counter * 2;`が実行されます。

`counter`は10なので、`10 * 2`、つまり`20`がループの結果として`result`変数に代入されました。このように、`break`に続けて値を書くことで、ループの「成果物」を持ち出すことができるのです。

ラベル付き`break`でネストしたloopを抜ける

ループ処理は、入れ子(ネスト)になることもあります。つまり、`loop`の中にさらに`loop`があるような構造です。

loop { // 外側のループ
    // ...
    loop { // 内側のループ
        // ...
        break; // ← これは内側のループしか抜けない!
    }
    // ...
}

内側のループで`break`を使っても、通常はその内側のループしか抜けられません。外側のループも一気に抜けたい場合はどうすればよいでしょうか?

そこで登場するのが「ラベル付き`break`」です。ループの前に `'ラベル名:` という形式でラベルを付け、`break 'ラベル名;` のように書くことで、指定したラベルが付いているループを直接抜けることができます。

例を見てみましょう。

fn main() {
    let mut count = 0;
    println!("外側のループを開始");

    'outer: loop { // 外側のループに 'outer というラベルを付ける
        println!("外側ループ処理: count = {}", count);
        let mut remaining = 10;
        println!("  内側のループを開始");

        loop { // 内側のループ (ラベルなし)
            println!("    内側ループ処理: remaining = {}", remaining);
            if remaining == 9 {
                println!("    remainingが9なので内側ループをbreak");
                break; // 内側のループだけ抜ける
            }
            if count == 2 {
                println!("    countが2なので'outerラベルのループをbreak!");
                break 'outer; // 'outerラベルが付いた外側のループを抜ける!
            }
            remaining -= 1;
        } // 内側ループの終わり

        count += 1;
        println!("  内側のループ終了、外側ループの末尾");
    } // 'outer ループの終わり

    println!("外側のループが終了しました。最終count: {}", count);
}

実行結果:

外側のループを開始
外側ループ処理: count = 0
  内側のループを開始
    内側ループ処理: remaining = 10
    内側ループ処理: remaining = 9
    remainingが9なので内側ループをbreak
  内側のループ終了、外側ループの末尾
外側ループ処理: count = 1
  内側のループを開始
    内側ループ処理: remaining = 10
    内側ループ処理: remaining = 9
    remainingが9なので内側ループをbreak
  内側のループ終了、外側ループの末尾
外側ループ処理: count = 2
  内側のループを開始
    内側ループ処理: remaining = 10
    countが2なので'outerラベルのループをbreak!
外側のループが終了しました。最終count: 2

`count`が2になったとき、内側のループで`break 'outer;`が実行され、外側のループごと処理が終了しているのがわかりますね。

ラベルを使うことで、複雑なループ構造でも意図した場所まで一気に脱出できるようになります。ラベル名はシングルクォート(`'`)で始めるのがルールです。

Rustのloopと他のループ(`while`, `for`)との違い

Rustには`loop`の他に、`while`ループと`for`ループがあります。それぞれの得意なこと、使い分けを簡単に整理しておきましょう。

  • `loop`
    • 用途: 条件なしの無限ループが基本。`break`で脱出や値の返却を制御する。
    • 得意なこと: 終了条件がループ内部のロジックで決まる場合、ループから値を返したい場合、リトライ処理など。
  • `while`
    • 用途: 指定した条件が真(true)の間、ループを繰り返す。
    • 得意なこと: ループの開始前に継続条件が決まっている場合。
    • 例: `while 条件式 { ... }`
  • `for`
    • 用途: 配列や範囲(Range)など、イテレータ(要素の集まりを順番にたどれるもの)の各要素に対して処理を繰り返す。
    • 得意なこと: コレクションの全要素を処理する場合。最も安全で推奨されることが多いループ。
    • 例: `for item in collection { ... }`

どのループを使うかは状況によりますが、「とりあえず無限ループを作って、後から条件で抜けたい」「ループの結果を値として得たい」という場面では、`loop`が活躍します。

Rustのloopを使う上での注意点

`loop`は便利ですが、いくつか気をつけておきたい点があります。

  • `break`の書き忘れに注意!
    `loop`は基本的に無限ループなので、`break`を書き忘れたり、`break`に到達する条件がいつまでも満たされなかったりすると、プログラムが意図せず停止しなくなる可能性があります。ループを抜ける条件は必ず設定しましょう。
  • ループ条件の変数を更新し忘れない
    `if`文などでループの終了条件を判定する場合、その条件で使われている変数がループ内でちゃんと変化するようにしないと、永遠にループを抜けられません。(例: `counter`を増やし忘れるなど)
  • ネストしたループでの`break`の挙動
    前述の通り、ネストした`loop`で単に`break`を使うと、一番内側のループしか抜けません。意図したループを抜けるために、必要に応じてラベル付き`break`を使いましょう。

これらの点に気をつければ、`loop`を安全かつ効果的に活用できますよ!

【まとめ】Rustのloopを理解して活用しよう

今回は、Rustの`loop`キーワードについて、基本的な使い方から応用までを解説しました!

  • `loop`は条件なしの無限ループを作成する。
  • `break`キーワードでループを終了できる。
  • `break 値;`の形で、ループから値を返すことができる(`loop`は式である!)。
  • ネストしたループから抜けるにはラベル付き`break`を使う。
  • `while`や`for`とは得意な場面が異なる。
  • `break`忘れによる無限ループには注意が必要。

`loop`は、一見すると原始的に見えるかもしれませんが、`break`と組み合わせることで柔軟な制御が可能になり、値を返せるという特徴も持っています。

Rustの基本的な制御フローの一つとして、ぜひ使い方をマスターしてください。

【関連記事】
Rustとは?いま学ぶべき理由と特徴や始め方を詳しく解説

このブログを検索

  • ()

自己紹介

自分の写真
リモートワークでエンジニア兼Webディレクターとして活動しています。プログラミングやAIなど、日々の業務や学びの中で得た知識や気づきをわかりやすく発信し、これからITスキルを身につけたい人にも役立つ情報をお届けします。 note → https://note.com/yurufuri X → https://x.com/mnao111

QooQ