Rust 里的制御フローは他の言語とほとんど変わりません。
if#
if の条件は () を付けずに、条件は bool 型である必要があります。
if は式です。JavaScript の 三項演算子 と同じ効果が得られます。
let x = if true { 1 } else { 2 };
ループ#
ループ制御の loop は以前見たことがありませんが、無限ループです。break と continue を使用して終了やスキップを制御します。Rust では break に値を返すこともできます。break、continue、およびループラベルの概念は、JavaScript の for でもありますが、ES6 の習慣に慣れているため、あまり触れたことはありません。
標準ライブラリの Range と for を組み合わせると面白い感じがします。JavaScript でループを書くときは、ループ回数を制御する簡潔な方法が欲しいと思っていましたが、これで満足です。
match#
match は JavaScript の switch に似ていますが、すべての可能性が網羅されていることを厳密にチェックします。[[データ型 #列挙型]] と組み合わせて、列挙型のメンバーに含まれる値をマッチングおよび抽出することができます。
let value = match some_value {
Some(i) => i,
None => 0
};
other または _ を使用して他のシナリオを処理することもできます。ワイルドカードは通常、最後の条件に書かれるべきです。そうしないと、後に書かれた条件は完全に無効になります。
match some_num {
1 => call(),
3 => check(),
other => println!("{}", other),
// または具体的な値を取得しないために _ を使用することもできます
// _ => (),
};
if let#
1 つのシナリオのみを処理する場合、if let 構文を使用するとより簡潔になりますが、match と比べて網羅性のチェックが少なくなります。
if let Some(value) = some_value {
println!("{}", value);
}
? 演算子#
JavaScript のオプショナルチェイニングに似た ? 演算子は、Option と Result のエラーや None の値を伝播させるために使用されます。互換性のある戻り値の関数内でのみ使用できます。たとえば、Result を ? で使用するには、Result を返す必要があります。異なる点は、Result を関数のどの位置でも使用できることです。これにより、事前に中断して Result::Err を返すことができます。
パターンマッチング#
パターンは、Rust で型構造をマッチングするための構文です。JavaScript の 分割代入 に少し似ていますが、少し論理的な逆の思考方法が必要です。ただし、使用できるシナリオが多く、制御フローのほとんどはパターンマッチングで行うことができます。
let 文はパターンマッチングに使用できます。= の左側のパターンが右側の式とマッチングされます。match のブランチでは、=> の左側のパターンが match キーワードの右側の式とマッチングされます。if let 文では、= の左側のパターンが右側の式とマッチングされます。
let (x, y) = (1, 2);
match some_value {
Some(4) | Some(5) => {},
Some(x) => {},
None => {}
}
if let 1..=3 = some_value {
} else if is_true {
} else {
}
// 構造体の分割
let User { name: username, age } = user;
これにより、if let が if (パターンマッチング結果) のように見えることがわかります。
反駁可能性#
式にパターンがマッチングしない可能性がある場合、そのパターンは反駁可能です。たとえば、match のブランチ条件などです。逆に、すべての可能性が網羅されている場合は、反駁不可能なパターンと言えます。let や for は反駁不可能なパターンのみを受け入れます。
値を無視するパターン#
_を使用して単一の値を無視できます。パターン内で複数回使用することもできます。..を使用して残りの値を無視できますが、曖昧さがないことを確認する必要があります。
マッチングガード#
match のブランチ条件の後に if キーワードを使用してガードを追加できます。つまり、追加のマッチング条件です。
match some_value {
Some(1) | Some(2) => {},
Some(v) if v > 0 => {},
Some(_) => {},
_ => {}
}
追加された if は前のパターン全体に適用されます。複数のパターンを指定するために | 演算子を使用した場合、if の方が優先度が高くなります。これによって、今後はこの点に注意することになるでしょう。
match x {
// ここでは x が何であってもマッチングしません
1 | 2 | 3 if false => {},
_ => {}
}
変数を取得しながらパターンをマッチングする場合は、@ バインディングを使用できます。
match user {
// ここでは age をマッチングに使用し、後のブロックではアクセスできません
User { age: 1..=18, .. } => {},
// これでアクセスできます
User { age: user_age @ 20..=35, .. } => {}
}