コンテンツにスキップ

Rustのfor

for は、範囲やコレクションを1つずつ順番にたどっていくループです。Rustの3種類のループの中で、いちばんよく使うことになるのがこの for です。

fn main() {
for i in 1..=5 {
println!("{i}");
}
}

実行結果:

1
2
3
4
5
▶ 実際に試してみよう

1..=5 は両端を含む範囲(range)で、1から5までを表します。= を取って 1..5 にすると1つ手前で止まり、1から4までになります。この「1つずれる」間違いはうっかりやりがちなので、どちらのつもりで書いたのか確認するくせをつけましょう。

for が本領を発揮するのはここです。インデックスを自分で管理しなくても、配列やベクタを順にたどれます。

fn main() {
let fruits = ["りんご", "バナナ", "さくらんぼ"];
for fruit in fruits {
println!("{fruit}");
}
}

実行結果:

りんご
バナナ
さくらんぼ
▶ 実際に試してみよう

while ループで自分で数を数えてインデックス(fruits[i])でアクセスする書き方と比べてみてください。こちらのほうが短く、インデックスを間違える心配もありません。配列とベクタについては、配列とベクタのページで詳しく学びます。

.enumerate()でインデックスも受け取る

Section titled “.enumerate()でインデックスも受け取る”

位置と値の両方が必要なら、.enumerate() を使います。

fn main() {
let fruits = ["りんご", "バナナ", "さくらんぼ"];
for (index, fruit) in fruits.iter().enumerate() {
println!("{index}: {fruit}");
}
}

実行結果:

0: りんご
1: バナナ
2: さくらんぼ
▶ 実際に試してみよう

(index, fruit) の部分はタプルのパターンです。1回まわるごとにペアが渡され、ループがそれを2つの変数に分けてくれます。

逆順に数える・飛ばしながら数える

Section titled “逆順に数える・飛ばしながら数える”

3からカウントダウンしたいときや、1つおきの数だけを扱いたいときはどうすればよいでしょう?最初に思いつくのは、3..=1 のような逆向きの範囲かもしれません。これはコンパイルできますが、ループは一度も実行されません。範囲は上向きにしか数えないので、始まりが終わりより大きい範囲は、ただの空っぽの範囲になるのです。

代わりに、ふつうの範囲を用意して、そのたどり方を変えます。

  • .rev() は範囲を逆順にたどります。
  • .step_by(n) は最初の値から始めて、n 個ごとに値を取り出します。
fn main() {
for i in (1..=3).rev() {
println!("{i}...");
}
println!("スタート!");
for even in (0..=10).step_by(2) {
print!("{even} ");
}
println!();
for i in 3..=1 {
println!("これは表示されない: {i}");
}
}

実行結果:

3...
2...
1...
スタート!
0 2 4 6 8 10
▶ 実際に試してみよう

(1..=3).rev() のカッコに注目してください。カッコがないと、Rustは 1..=3.rev() を「1から 3.rev() まで」と読んでしまい、意図とは違うものになります。2つを組み合わせることもできます。(0..=10).rev().step_by(5) なら10、5、0になります。

数を数えるならwhileよりforがよい理由

Section titled “数を数えるならwhileよりforがよい理由”

数を数えるループは while でも書けます。でも範囲を使った for なら、よくある間違いをまるごと防げます。カウンタを更新し忘れることもなければ、配列の終わりを1つ越えてしまう心配もありません。Rustのプログラマーは基本的に for を使い、ループの対象になる自然な範囲やコレクションがないときだけ while を使います。

7 x 1 = 7 から 7 x 10 = 70 まで、7の段を表示してください。ヒント:1..=10 に対する for ループが1つあれば十分です。掛け算は println! の中で直接できます。

解答を見る
fn main() {
for i in 1..=10 {
println!("7 x {i} = {}", 7 * i);
}
}

実行結果:

7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70
▶ 実際に試してみよう

{i} のような変数名は、波カッコの中に直接書けます。でも 7 * i のような計算は書けないので、空の {} を使い、カンマの後ろに値を渡しています。

1から99までの奇数をすべて足して、合計を表示してください。ヒント:(1..100).step_by(2) で1、3、5、…、99が得られます。ループの外に mut の合計を用意しましょう。

解答を見る
fn main() {
let mut total = 0;
for n in (1..100).step_by(2) {
total += n;
}
println!("1から99までの奇数の合計は{total}です");
}

実行結果:

1から99までの奇数の合計は2500です
▶ 実際に試してみよう

別の方法として、1..100 をループして、n % 2 == 1 のときだけ n を足すこともできます。どちらでも正解です。step_by は、1つずつチェックする代わりに偶数を飛ばしているだけです。

  • for 要素 in 範囲やコレクション { ... } は、Rustでふだん使いのループです。
  • 1..=5 は両端を含み、1..5 は5の1つ手前で止まります。
  • 配列やベクタを直接ループすれば、インデックスを使わずに各値を受け取れます。
  • 値と一緒にインデックスも必要なときは .enumerate() を使います。
  • 3..=1 のような逆向きの範囲は空です。カウントダウンには (1..=3).rev() を、飛ばしながら進むには .step_by(n) を使います。

理解度チェック

1. forループで使う 1..=5 と 1..5 の違いは何ですか?

2. コレクションをループしながら、インデックスと値の両方を受け取るにはどうしますか?

3. コレクションを順に数えていくとき、ふつう while より for が好まれるのはなぜですか?

4. for i in 5..=1 { ... } はどうなりますか?

スコア: 0 / 4