Rustを用いた開発において、プログラムの実行フローを効率的に制御することは、パフォーマンスと可読性の両面で極めて重要です。
反復処理の中で特定の条件が満たされた際、それ以降の処理をスキップして次のループ回に進みたい場面は頻繁に発生します。
Rustでは、このような制御を明快に記述するためのキーワードとしてcontinue文が用意されています。
本記事では、continue文の基本的な使い方から、実務で役立つラベル付きループへの活用方法までを詳しく解説します。
Rustにおけるcontinue文の役割
continue文は、ループの現在の反復処理を中断し、直ちに次の反復の開始地点へ制御を移すための制御フロー演算子です。
この命令が実行されると、ループブロック内にあるcontinue以降のコードは実行されません。
Rustにはfor、while、loopという3種類のループ構造がありますが、continueはいずれの構文でも共通して使用可能です。
適切に活用することで、ネストしたif文を回避し、コードのインデントを浅く保つ「ガード節」のような役割を果たします。
continue文の基本構文と実装例
まずは、最も標準的なforループにおけるcontinue文の使い方を確認しましょう。
forループでの利用
特定の数値だけを除外して処理を行いたい場合、continueは非常に有効です。
// 1から5までの数値のうち、奇数だけを出力する例
fn main() {
for i in 1..=5 {
// 数値が偶数の場合は、以降の処理をスキップして次の数値へ
if i % 2 == 0 {
continue;
}
println!("現在の数値: {}", i);
}
}
現在の数値: 1
現在の数値: 3
現在の数値: 5
この例では、i % 2 == 0という条件が真になったとき、println!を呼び出さずにループの先頭に戻っています。
whileループでの利用
whileループでも同様にcontinueを使用できますが、変数の更新タイミングには注意が必要です。
fn main() {
let mut count = 0;
while count < 5 {
count += 1;
if count == 3 {
println!("3をスキップします");
continue;
}
println!("カウント: {}", count);
}
}
カウント: 1
カウント: 2
3をスキップします
カウント: 4
カウント: 5
もしcount += 1の更新処理をcontinueの後ろに記述してしまうと、無限ループに陥る危険性があります。
ラベル付きループ(Loop Labels)による高度な制御
Rustの強力な機能の一つに、ループに名前を付ける「ループラベル」があります。
多重ループ(入れ子のループ)を使用している際、内側のループから外側のループに対してcontinueを適用することが可能です。
ラベル付きループの構文
ラベルは 'ラベル名: という形式で定義し、continue 'ラベル名; と記述することで指定したループを制御します。
fn main() {
// 外側のループに 'outer というラベルを付与
'outer: for x in 1..4 {
for y in 1..4 {
if x == 2 && y == 2 {
println!(" (x:2, y:2) を検知。外側ループの次へ移動します。");
// 内側のループではなく、外側の 'outer ループを continue する
continue 'outer;
}
println!("x: {}, y: {}", x, y);
}
}
}
x: 1, y: 1
x: 1, y: 2
x: 1, y: 3
x: 2, y: 1
(x:2, y:2) を検知。外側ループの次へ移動します。
x: 3, y: 1
x: 3, y: 2
x: 3, y: 3
実行結果を見ると、x == 2 && y == 2 のタイミングで y: 3 の処理が行われず、即座に x: 3 の処理が始まっていることがわかります。
この機能がない言語では、フラグ変数を用意して複数のif文で制御する必要がありますが、Rustでは非常に簡潔に記述できます。
continue文とbreak文の比較
ループ制御において、continueと混同されやすいのがbreak文です。
これら二つの違いを正確に理解しておくことは、バグの少ないプログラムを書くための第一歩です。
| キーワード | 動作の内容 | 主な用途 |
|---|---|---|
continue | 現在の反復のみをスキップし、次の回へ進む | 特定の条件に合致するデータのみ除外したいとき |
break | ループそのものを完全に終了する | 目的のデータが見つかったときや、異常終了させたいとき |
continueは「今回の処理は終わりだが、次はやる」、breakは「このループ自体をもうやめる」という明確な違いがあります。
実践的な活用シーンとベストプラクティス
実際の開発現場では、continueはどのように使われるのが理想的なのでしょうか。
ガード節としての利用
複雑な条件分岐が続くループ内では、最初に「処理したくない条件」をcontinueで弾く手法が推奨されます。
for item in items {
if !item.is_active() {
continue;
}
if item.price() == 0 {
continue;
}
// ここからメインの処理を記述
process(item);
}
このように記述することで、メインの処理がif文のネストに埋もれるのを防ぎ、コードの可読性を劇的に向上させることができます。
イテレータのfilterメソッドとの使い分け
Rustには関数型プログラミングのスタイルで記述できるイテレータが存在します。
単純なフィルタリングであれば、filterメソッドを使用する方がRustらしい(Idiomaticな)コードになる場合があります。
しかし、処理の途中で副作用(ログ出力や複雑な状態更新)を伴う場合は、命令的なforループとcontinueを組み合わせる方が意図を伝えやすいこともあります。
Rustの型安全性とcontinue文
Rustのコンパイラは非常に強力であり、continueを使用する際も型整合性や生存期間(ライフタイム)を厳格にチェックします。
例えば、loop式から値を返そうとする際、continueが含まれるパスがあると値の型が不一致にならないよう注意が必要です。
もっとも、continue自体は「何も返さない」という性質を持つため、通常はユニット型 () と同様に扱われ、制御フロー解析において適切に処理されます。
まとめ
Rustにおけるcontinue文は、ループ処理を柔軟かつ安全に制御するための重要なツールです。
基本的な次の回へのスキップはもちろん、ラベル付きループを活用することで複雑な多重ループも直感的に記述できます。
条件が複雑になるほど、ガード節としてのcontinueの真価が発揮されます。
今回紹介した基本ルールとラベルの活用法をマスターして、よりクリーンで効率的なRustコードを書き上げましょう。
今後、さらに高度な並行処理や非同期ループを扱う際にも、この制御フローの基本知識が大きな助けとなるはずです。
