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, .. } => {}
}