Rustのforを完全マスター!イテレータの基礎から実践まで

2025年4月20日日曜日

Rust

Rustのforループ、使いこなせていますか? プログラミングではお馴染みの繰り返し処理ですが、Rustのforループは、実はとっても奥が深いんです。

この記事では、Rustのforループの基本的な書き方から、ちょっと応用的な使い方、そしてRustらしさの核心とも言える「イテレータ」の考え方まで、しっかり解説していきますよ。

「なんか難しそう…」と感じている方も、大丈夫。豊富なサンプルコードと、できるだけ簡単な言葉で説明するので、読み終わるころには「なるほど、わかった!」となっているはずです。

この記事でわかること

  • Rustのforループの基本的な書き方がわかる
  • 数字の範囲を指定して繰り返し処理ができる
  • 配列やベクタの中身を順番に処理できる
  • Rustの重要な仕組み「イテレータ」の基本がわかる
  • ループ中に要素の番号(インデックス)も取得できる
  • ループを途中で抜けたり、スキップしたりする方法がわかる

Rustのforループとは?繰り返し処理の基本を理解しよう

まず、forループって何? というところから始めましょう。

簡単に言うと、同じような処理を何度も繰り返したいときに使う命令のことです。例えば、

  • 数字を1から10まで順番に表示したい
  • リストに入っている名前を一人ずつ挨拶したい
  • テストの点数を集計したい

みたいに、決まった回数や、データの数だけ何かをしたいときに大活躍します。

他のプログラミング言語にも似たような仕組みはありますが、Rustのforループは特に「イテレータ」という仕組みと仲良しなんです。

このイテレータについては後で詳しく説明しますが、今は「何かを順番に処理するのが得意なんだな」くらいに思っておいてくださいね。

Rustのforループ:基本的な書き方

では、早速Rustのforループの基本的な形を見てみましょう。一番シンプルな形はこんな感じです。

for 変数 in コレクションや範囲 {
    // ここに繰り返したい処理を書く
}

分解してみましょう。

  • for: これからforループを始めるよ、という合図です。
  • 変数: 繰り返しの中で、コレクションや範囲から取り出した一つ一つの要素が入る箱(変数)です。名前は自由につけられます。
  • in: 変数とコレクションや範囲をつなぐ言葉です。
  • コレクションや範囲: 繰り返したいデータの集まりや、数値の範囲などを指定します。配列、ベクタ、文字列、数値の範囲などが使えます。
  • { }: この波括弧の中に、繰り返したい具体的な処理を書きます。

言葉だけだとピンとこないかもしれないので、簡単な例を見てみましょう。
例えば、0から2までの数字を順番に表示するには、こう書きます。

書き方

fn main() {
    for i in 0..3 {
        println!("現在の数値: {}", i);
    }
}

ソースコードの表示結果

現在の数値: 0
現在の数値: 1
現在の数値: 2

この例では、0..3 が「0から3の手前まで(つまり0, 1, 2)」という数値の範囲を表しています。

ループが回るたびに、変数 i に 0, 1, 2 が順番に入り、println! で表示されているのがわかりますね。これがforループの基本です!

Rustのforループの使い方① - 数値範囲の繰り返し

先ほどの例でも少し出てきましたが、forループは数値の範囲を指定して、決まった回数だけ処理を繰り返すのが得意です。

Rustでは、範囲の指定方法が主に2種類あります。使い分けると便利なので、両方覚えておきましょう!

a..b形式(終点を含まない範囲)

これは、a から始まって b手前まで繰り返す書き方です。数学で言うと `a <= x < b` の範囲ですね。

書き方

fn main() {
    println!("1から4の手前まで表示します:");
    for number in 1..4 {
        println!("数値: {}", number);
    }
}

ソースコードの表示結果

1から4の手前まで表示します:
数値: 1
数値: 2
数値: 3

見ての通り、1..4 と書くと、1, 2, 3 までが処理されて、終点の数値である 4 は含まれない点に注意しましょう。プログラミングでは、このように終点を含まない範囲指定がよく使われます。

a..=b形式(終点を含む範囲)

こちらは、a から始まって b まで、つまり終点の数値も含めて繰り返す書き方です。= が付いているのが目印ですね。数学だと `a <= x <= b` になります。

書き方

fn main() {
    println!("1から3まで表示します:");
    for number in 1..=3 {
        println!("数値: {}", number);
    }
}

ソースコードの表示結果

1から3まで表示します:
数値: 1
数値: 2
数値: 3

今度は 1..=3 と書いたので、1, 2, 3 と、終点の数値もちゃんと含まれる形で処理されました。ぴったり指定した回数だけ繰り返したい場合に便利です。

Rustのforループの使い方② - コレクション(配列・ベクタ)の繰り返し

数値の範囲だけでなく、配列やベクタといった「データの集まり」(コレクション)の中身を一つずつ順番に見ていくのも、forループの得意技です。むしろ、こちらの使い方のほうが出番が多いかもしれません。

例えば、買い物リストに入っている商品を全部表示したり、テストの点数がたくさん入ったリストから平均点を計算したり…そんな時に役立ちます。

配列やベクタの要素を順番に取り出す

配列やベクタをforループで使うのは、とても簡単です。

書き方(配列の例)

fn main() {
    let fruits = ["りんご", "バナナ", "みかん"];
    println!("果物リスト:");
    for fruit in fruits.iter() { // .iter() を使うのが一般的
        println!("- {}", fruit);
    }
}

ソースコードの表示結果

果物リスト:
- りんご
- バナナ
- みかん

書き方(ベクタの例)

fn main() {
    let scores = vec![85, 92, 78];
    println!("テストの点数:");
    for score in &scores { // & をつける方法もある
        println!("{} 点", score);
    }
}

ソースコードの表示結果

テストの点数:
85 点
92 点
78 点

配列 fruits やベクタ scores の中身が、ループ変数 fruitscore に順番に入って処理されているのがわかりますね。このように、コレクションの各要素に順番にアクセスできるのがforループの強みです。

ところで、上の例で .iter()& が付いているのに気づきましたか? 次は、これらがなぜ必要なのかを見ていきましょう。

なぜ「&」が必要?所有権とイテレータの基礎

Rustには「所有権」という、他の言語にはあまりない重要なルールがあります。すごく簡単に言うと、「データ(値)の持ち主は一人だけ」というルールです。

もし、forループでコレクションをそのまま使ってしまうと、ループが終わったときにコレクションの所有権がforループに移ってしまい、元の変数が使えなくなってしまうことがあるんです。(ちょっと困りますよね!)

そこで登場するのが「参照」と「イテレータ」です。

  • 参照 (&): データの所有権を移動させずに、データを「借りて」くる方法です。for score in &scores のように書くと、scores の所有権はそのままに、中身を借りてループできます。
  • イテレータ (.iter()): コレクションから要素を順番に取り出すための仕組み(オブジェクト)を作るメソッドです。fruits.iter() は、fruits の各要素への「参照」を順番に提供するイテレータを作ります。これも所有権は移動しません。

どちらを使っても、元のコレクションの所有権を保ったままループ処理ができます。最初は少しややこしく感じるかもしれませんが、基本は .iter() を使って、元のデータを「借りてくる」イメージでいると安全確実です。これがRustらしい書き方の一つなんです。

所有権やイテレータはもっと奥が深いのですが、forループを使う上ではまず「データを直接使わず、参照(&.iter())を使うのが基本」と覚えておきましょう。

要素を書き換えたい場合 (.iter_mut())

ループの中で、コレクションの要素の値を変更したい場面もありますよね。例えば、ベクタに入っている数値を全部2倍にしたい、とか。

そんなときは、.iter() の代わりに .iter_mut() を使います。mut は "mutable"(変更可能)の略です。これを使うと、要素への「変更可能な参照」を取り出すことができます。

ただし、.iter_mut() を使うには、元のコレクション自体も変更可能 (mut) である必要があります。

書き方

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];
    println!("元の数値: {:?}", numbers);

    // .iter_mut() で変更可能な参照を取得
    for num in numbers.iter_mut() {
        *num *= 2; // * で参照先の値を変更
    }

    println!("2倍した後の数値: {:?}", numbers);
}

ソースコードの表示結果

元の数値: [1, 2, 3, 4, 5]
2倍した後の数値: [2, 4, 6, 8, 10]

まず、ベクタ numberslet mut で宣言して変更可能にしています。
次に numbers.iter_mut() でループし、ループ変数 num は各要素への「変更可能な参照」 (&mut i32 型) になります。

要素の値を変更するには、*num のようにアスタリスク * を付けて参照先の値にアクセスし、それに2を掛けています。

結果として、元のベクタの値が書き換えられているのがわかりますね。要素を書き換えるときは .iter_mut()mut が必要だと覚えておきましょう。

Rustのforループでインデックス付きで繰り返す (.enumerate())

ループ処理をしていると、「今、何番目の要素を処理しているのか」というインデックス(添字)番号も一緒に知りたい場合がありますよね。

そんなときに便利なのが .enumerate() メソッドです。イテレータに対してこのメソッドを呼び出すと、(インデックス, 要素) というペアを順番に返してくれるようになります。

書き方

fn main() {
    let tasks = vec!["メール返信", "資料作成", "会議"];

    println!("今日のタスク:");
    // .iter() でイテレータを取得し、.enumerate() でインデックスを付与
    for (index, task) in tasks.iter().enumerate() {
        // インデックスは0から始まる
        println!("{}: {}", index + 1, task);
    }
}

ソースコードの表示結果

今日のタスク:
1: メール返信
2: 資料作成
3: 会議

tasks.iter().enumerate() とすることで、ループ変数に (index, task) という形で、0から始まるインデックスと要素の参照がセットで入るようになります。タプル(複数の値をまとめたもの)として受け取れるんですね。

表示するときに index + 1 としているのは、人間が見やすいように1から始まる番号にしているだけです。これで、何番目の処理なのかが一目瞭然になります!

Rustのforループを制御する (break, continue)

forループは基本的に指定された範囲やコレクションの最後まで処理を繰り返しますが、途中でループの動きを変えたい場合もあります。

  • break: ループを完全に中断して、ループの外に処理を移します。
  • continue: 現在の回の処理を途中でやめて、次の回の処理にスキップします。

それぞれの使い方を見てみましょう。

書き方(break の例)

fn main() {
    let numbers = [1, 2, 3, 4, 5, 6, 7];
    println!("5が見つかるまで探します:");
    for num in numbers.iter() {
        println!("チェック中: {}", num);
        if *num == 5 {
            println!("5を見つけました!ループを抜けます。");
            break; // ループを中断
        }
    }
    println!("ループが終わりました。");
}

ソースコードの表示結果

5が見つかるまで探します:
チェック中: 1
チェック中: 2
チェック中: 3
チェック中: 4
チェック中: 5
5を見つけました!ループを抜けます。
ループが終わりました。

num5 になった時点で if 文の中に入り、break が実行されます。すると、それ以降のループ(6や7のチェック)は行われず、forループ自体が終了しているのがわかりますね。

書き方(continue の例)

fn main() {
    println!("1から5までの奇数だけ表示します:");
    for i in 1..=5 {
        if i % 2 == 0 { // iが偶数だったら
            continue; // 今回の処理をスキップして次のループへ
        }
        // 奇数の場合だけここが実行される
        println!("奇数: {}", i);
    }
    println!("ループが終わりました。");
}

ソースコードの表示結果

1から5までの奇数だけ表示します:
奇数: 1
奇数: 3
奇数: 5
ループが終わりました。

i が偶数 (2, 4) の場合、if i % 2 == 0 が真になり、continue が実行されます。すると、その回の println! は実行されずに、すぐに次の i (3 や 5) の処理に移ります。結果として奇数だけが表示されていますね。

breakcontinue を使うと、ループの挙動を柔軟にコントロールできます。

【まとめ】Rustのforループを使いこなそう

 Rustのforループについて、基本的なところから少し応用的な使い方まで見てきました。

最後に、今回のポイントをまとめておきましょう。

  • forループは繰り返し処理の基本!
  • for 変数 in コレクションや範囲 {} の形で書く。
  • 数値範囲は a..b (bを含まない) と a..=b (bを含む) を使い分ける。
  • 配列やベクタは .iter() で回すのが基本(所有権のため)。
  • 要素を書き換えたいときは let mut.iter_mut() を使う。
  • インデックスも欲しいときは .enumerate() が便利。
  • ループを止めたいときは break、スキップしたいときは continue

Rustのforループは、裏側で「イテレータ」というパワフルな仕組みが動いています。最初は少し戸惑うかもしれませんが、慣れてくると非常に柔軟で効率的なコードが書けるようになりますよ。

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

このブログを検索

  • ()

自己紹介

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

QooQ