オプションとデフォルト値の展開

RustRustBeginner
今すぐ練習

This tutorial is from open-source community. Access the source code

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

この実験では、Option を展開するさまざまな方法を検討し、None の場合にはデフォルト値に切り替える方法について検討します。この際、即時評価や遅延評価、空の値をそのままにするか、置き換えるかなどの要因も考慮されます。

注: 実験でファイル名が指定されていない場合、好きなファイル名を使用できます。たとえば、main.rs を使用して、rustc main.rs &&./main でコンパイルして実行できます。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/DataTypesGroup -.-> rust/type_casting("Type Conversion and Casting") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99238{{"オプションとデフォルト値の展開"}} rust/mutable_variables -.-> lab-99238{{"オプションとデフォルト値の展開"}} rust/string_type -.-> lab-99238{{"オプションとデフォルト値の展開"}} rust/type_casting -.-> lab-99238{{"オプションとデフォルト値の展開"}} rust/function_syntax -.-> lab-99238{{"オプションとデフォルト値の展開"}} rust/expressions_statements -.-> lab-99238{{"オプションとデフォルト値の展開"}} rust/lifetime_specifiers -.-> lab-99238{{"オプションとデフォルト値の展開"}} rust/method_syntax -.-> lab-99238{{"オプションとデフォルト値の展開"}} rust/operator_overloading -.-> lab-99238{{"オプションとデフォルト値の展開"}} end

オプションとデフォルト値の展開

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: {:?}", first_available_fruit);
    // first_available_fruit: Some(Orange)

    // `or` はその引数を移動します。
    // 上の例では、`or(orange)` は `Some` を返したため、`or(apple)` は呼び出されませんでした。
    // ただし、`apple` という名前の変数は移動されており、もはや使用できません。
    // println!("Variable apple was moved, so this line won't compile: {:?}", apple);
    // TODO: 上の行をコメントアウト解除してコンパイラエラーを確認してください
 }

or_else() はチェーン可能で、遅延評価し、空の値をそのままに保つ

別の方法は、or_else を使用することです。これもチェーン可能で、遅延評価されます。以下の例に示すように:

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

fn main() {
    let apple = Some(Fruit::Apple);
    let no_fruit: Option<Fruit> = None;
    let get_kiwi_as_fallback = || {
        println!("Providing kiwi as fallback");
        Some(Fruit::Kiwi)
    };
    let get_lemon_as_fallback = || {
        println!("Providing lemon as fallback");
        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: {:?}", first_available_fruit);
    // Providing kiwi as fallback
    // 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 is: {:?}", first_available_fruit);
    println!("my_fruit is: {:?}", my_fruit);
    // first_available_fruit is: Apple
    // my_fruit is: Some(Apple)
    //println!("Variable named `apple` is moved: {:?}", 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!("Providing lemon as fallback");
        Fruit::Lemon
    };
    let first_available_fruit = my_fruit
     .get_or_insert_with(get_lemon_as_fallback);
    println!("first_available_fruit is: {:?}", first_available_fruit);
    println!("my_fruit is: {:?}", my_fruit);
    // Providing lemon as fallback
    // first_available_fruit is: Lemon
    // my_fruit is: 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 is: {:?}", should_be_apple);
    println!("my_apple is unchanged: {:?}", my_apple);
    // 出力は以下の通りです。クロージャ `get_lemon_as_fallback` は呼び出されません
    // should_be_apple is: Apple
    // my_apple is unchanged: Some(Apple)
}

まとめ

おめでとうございます!あなたは「オプションとデフォルト値の展開」の実験を完了しました。あなたの技術を向上させるために、LabExでさらに多くの実験を行って練習してください。