Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Option とデフォルト値を展開する

Option を展開し、それが None の場合にデフォルト値へフォールバックする方法は複数あります。ニーズに合うものを選ぶには、次の点を考慮する必要があります。

  • 即時評価と遅延評価のどちらが必要か?
  • 元の空の値をそのまま保持する必要があるか、それともインプレースで変更する必要があるか?

or() はチェーン可能で、即時評価され、空の値をそのまま保持する

次の例に示すように、or() はチェーン可能で、引数を即時評価します。or の引数は即時評価されるため、or に渡された変数はムーブされることに注意してください。

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let apple = Some(Fruit::Apple);
    let orange = Some(Fruit::Orange);
    let no_fruit: Option<Fruit> = None;

    let first_available_fruit = no_fruit.or(orange).or(apple);
    println!("最初に利用可能な果物: {:?}", first_available_fruit);
    // 最初に利用可能な果物: Some(Orange)

    // `or` は引数をムーブします。
    // 上の例では、`or(orange)` が `Some` を返したため、`or(apple)` は呼び出されませんでした。
    // しかし、`apple` という名前の変数はそれでもムーブされており、もう使用できません。
    // println!("変数 apple はムーブされたため、この行はコンパイルされません: {:?}", apple);
    // TODO: コンパイラエラーを確認するには、上の行のコメントを外してください
}

or_else() はチェーン可能で、遅延評価され、空の値をそのまま保持する

別の選択肢は or_else を使うことです。これもチェーン可能で、次の例に示すように遅延評価されます。

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let no_fruit: Option<Fruit> = None;
    let get_kiwi_as_fallback = || {
        println!("フォールバックとしてキウイを提供します");
        Some(Fruit::Kiwi)
    };
    let get_lemon_as_fallback = || {
        println!("フォールバックとしてレモンを提供します");
        Some(Fruit::Lemon)
    };

    let first_available_fruit = no_fruit
        .or_else(get_kiwi_as_fallback)
        .or_else(get_lemon_as_fallback);
    println!("最初に利用可能な果物: {:?}", first_available_fruit);
    // フォールバックとしてキウイを提供します
    // 最初に利用可能な果物: Some(Kiwi)
}

get_or_insert() は即時評価され、空の値をインプレースで変更する

Option に値が含まれていることを確実にするには、次の例に示すように、get_or_insert を使ってフォールバック値でインプレースに変更できます。get_or_insert はパラメータを即時評価するため、変数 apple はムーブされることに注意してください。

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let mut my_fruit: Option<Fruit> = None;
    let apple = Fruit::Apple;
    let first_available_fruit = my_fruit.get_or_insert(apple);
    println!("first_available_fruit は: {:?}", first_available_fruit);
    println!("my_fruit は: {:?}", my_fruit);
    // first_available_fruit は: Apple
    // my_fruit は: Some(Apple)
    //println!("`apple` という名前の変数はムーブされました: {:?}", apple);
    // TODO: コンパイラエラーを確認するには、上の行のコメントを外してください
}

get_or_insert_with() は遅延評価され、空の値をインプレースで変更する

フォールバック先の値を明示的に提供する代わりに、次のようにクロージャを get_or_insert_with に渡すことができます。

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let mut my_fruit: Option<Fruit> = None;
    let get_lemon_as_fallback = || {
        println!("フォールバックとしてレモンを提供します");
        Fruit::Lemon
    };
    let first_available_fruit = my_fruit
        .get_or_insert_with(get_lemon_as_fallback);
    println!("first_available_fruit は: {:?}", first_available_fruit);
    println!("my_fruit は: {:?}", my_fruit);
    // フォールバックとしてレモンを提供します
    // first_available_fruit は: Lemon
    // my_fruit は: Some(Lemon)

    // Option に値がある場合、それは変更されず、クロージャは呼び出されません
    let mut my_apple = Some(Fruit::Apple);
    let should_be_apple = my_apple.get_or_insert_with(get_lemon_as_fallback);
    println!("should_be_apple は: {:?}", should_be_apple);
    println!("my_apple は変更されていません: {:?}", my_apple);
    // 出力は次のとおりです。クロージャ `get_lemon_as_fallback` は呼び出されないことに注意してください
    // should_be_apple は: Apple
    // my_apple は変更されていません: Some(Apple)
}

関連項目:

クロージャ, get_or_insert, get_or_insert_with, ムーブされた変数, or, or_else