? で Option を展開する
Option は match 文を使って展開できますが、多くの場合は ? 演算子を使う方が簡単です。x が Option の場合、x? を評価すると、x が Some なら内側の値を返し、そうでなければ現在実行中の関数を終了して None を返します。
fn next_birthday(current_age: Option<u8>) -> Option<String> {
// `current_age` が `None` の場合、これは `None` を返します。
// `current_age` が `Some` の場合、内側の `u8` 値 + 1 が
// `next_age` に代入されます
let next_age: u8 = current_age? + 1;
Some(format!("来年、私は{}歳になります", next_age))
}
複数の ? を連鎖させることで、コードをずっと読みやすくできます。
struct Person { job: Option<Job>, } #[derive(Clone, Copy)] struct Job { phone_number: Option<PhoneNumber>, } #[derive(Clone, Copy)] #[allow(dead_code)] struct PhoneNumber { area_code: Option<u8>, number: u32, } impl Person { // 存在する場合、その人の仕事の電話番号の市外局番を取得します。 fn work_phone_area_code(&self) -> Option<u8> { // `?` 演算子がなければ、これは多くのネストした `match` 文が必要になります。 // もっと多くのコードが必要になります。自分で書いてみて、どちらが // 簡単か確かめてください。 self.job?.phone_number?.area_code } } fn main() { let p = Person { job: Some(Job { phone_number: Some(PhoneNumber { area_code: Some(61), number: 439222222, }), }), }; assert_eq!(p.work_phone_area_code(), Some(61)); }