forループ

for と range

for in構文を用いることで、イテレータのそれぞれの要素に対して処理をすることが可能です。イテレータを作る最も単純な方法はa..bのような範囲記法です。これは「a」から「bのひとつ前」までの要素を順に生成します。

ではwhileの代わりにforを用いてFizzBuzzを書いてみましょう。

fn main() {
    // `n`は1, 2, ...., 100のそれぞれの値を取ります。
    for n in 1..101 {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }
    }
}

上記の代わりにa..=bを用いると、両端の値を含む範囲を指定できます。上記の例は次のように書けます。

fn main() {
    // `n`は1, 2, ...., 100のそれぞれの値を取ります。
    for n in 1..=100 {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }
    }
}

forとイテレータ

for in構文はイテレータとさまざまな方法でやり取りできます。Iteratorトレイトの章で説明したように、デフォルトではforループにおいてinto_iter関数がコレクションに対して適用されます。しかし、コレクションをイテレータに変換する方法はこれだけではありません。

into_iteriteriter_mutはいずれもコレクションのイテレータへの変換を行いますが、データの「見せ方」の違いにより、そのやり方はそれぞれ異なります。

  • iter - この関数は、各周回においてコレクションの要素を借用します。よってコレクションには手を加えないので、ループの実行後もコレクションを再利用できます。
fn main() {
    let names = vec!["Bob", "Frank", "Ferris"];

    for name in names.iter() {
        match name {
            &"Ferris" => println!("There is a rustacean among us!"),
            // TODO ^ Try deleting the & and matching just "Ferris"
            _ => println!("Hello {}", name),
        }
    }
    
    println!("names: {:?}", names);
}
  • into_iter - この関数はコレクションからデータを取り出すので、各周回において要素のデータそのものが提供されます。データを取り出してしまうと、データはループ内に「移動」してしまうので、ループ実行後にコレクションを再利用することはできません。
fn main() {
    let names = vec!["Bob", "Frank", "Ferris"];

    for name in names.into_iter() {
        match name {
            "Ferris" => println!("There is a rustacean among us!"),
            _ => println!("Hello {}", name),
        }
    }
    
    println!("names: {:?}", names);
    // FIXME ^ この行をコメントアウトしましょう
}
  • iter_mut - この関数はコレクションの各要素をミュータブル(変更可能)で借用するので、コレクションの要素をその場で変更できます。
fn main() {
    let mut names = vec!["Bob", "Frank", "Ferris"];

    for name in names.iter_mut() {
        *name = match name {
            &mut "Ferris" => "There is a rustacean among us!",
            _ => "Hello",
        }
    }

    println!("names: {:?}", names);
}

上記に示した3つのコードにおいて、matchの選択肢の型の違いに注意してください。ここがそれぞれの方法の違いを生む鍵になっています。型が異なれば、当然ながらそれに対して行える処理も変わります。

参照

イテレータ