// dictionary
for式.
for式は、イテレータが生み出す要素を順に取り出し、要素ごとに本体のブロックを実行するループです。for パターン in 式 { ... }の形で書き、inの右側にはイテレータに変換できる値(範囲式・配列型・ベクタ(Vec)など)を置きます1。要素がなくなれば自動で終了するため繰り返し回数の管理が要らず、3種類のループの中で最もよく使う構文です。名前のとおり全体が1つの式ですが、その値は常にユニット型()で、loop式と違いbreakで値を返せません。
fn main() {
let prices = [120, 250, 80]; // 買い物かごの中身
let mut total = 0;
for price in prices {
total += price;
}
println!("合計: {total}円");
}Playgroundで開くコレクションの渡し方は3通り
ベクタのようなコレクションは、inにそのまま渡すか参照で渡すかで、取り出せる要素の型が変わります。
| 書き方 | 要素の型 | 主な用途 |
|---|---|---|
for x in &v |
&T(参照) |
読み取りだけ行う |
for x in &mut v |
&mut T(排他参照) |
要素を書き換える |
for x in v |
T(所有権が移る) |
要素を消費する |
そのまま渡すと所有権がループに移り、ベクタのようなCopyでない型ではループの後で元の変数を使えなくなります(冒頭の例の配列は要素がCopyのため配列ごとコピーが渡り、後でも使えます)。読み取りだけなら&vで渡すのが基本です。
補足
添字が必要なとき — enumerate
要素と一緒に「何番目か」も使いたいときは、添字を自前で管理するのではなくenumerateを使います。添字と要素のペアがタプル型の値として順に得られます(添字は0始まり)。
fn main() {
let menu = ["カレー", "ラーメン", "うどん"];
for (index, name) in menu.iter().enumerate() {
println!("{}番: {name}", index + 1); // 表示用に+1します(enumerate自体は0始まり)
}
}Playgroundで開くfor式はloop式への糖衣構文
for式はコンパイル時に、IntoIterator::into_iterでイテレータを作り、loopの中でIterator::nextを呼び続ける形へ展開されます1。nextがOption型のSome(値)を返す間だけ本体を実行し、Noneになったらbreakします。inの左側には、このSomeから取り出した値が束縛されるため、必ずマッチするパターン(irrefutableパターン)しか書けません。
他言語のfor文との違い
JavaScriptやC言語にあるfor (let i = 0; i < 3; i++)のような「カウンタ変数を初期化・条件判定・更新する」形式のfor文は、Rustには存在しません(forの構文はイテレータを回す形式だけです1)。
| 言語 | 代表的な書き方 |
|---|---|
| JavaScript(C形式) | for (let i = 0; i < 3; i++) { ... } |
JavaScript(for...of) |
for (const item of items) { ... } |
| Rust | for i in 0..3 { ... }・for item in &items { ... } |
Rustのforが相当するのはJavaScriptのfor...ofで、カウンタで回したいときは範囲式を渡します。添字と終了条件を手書きするカウンタ形式は、条件の書き間違いで配列の範囲外を指してパニックしたり要素を取りこぼしたりするバグの温床になるため、Rustではイテレータ形式のforが安全かつ簡潔な定番とされています2。
Footnotes
この辞書が使われているページ
backlinks 8