はじめに
この実験では、Option
を展開するさまざまな方法を検討し、None
の場合にはデフォルト値に切り替える方法について検討します。この際、即時評価や遅延評価、空の値をそのままにするか、置き換えるかなどの要因も考慮されます。
注: 実験でファイル名が指定されていない場合、好きなファイル名を使用できます。たとえば、
main.rs
を使用して、rustc main.rs &&./main
でコンパイルして実行できます。
This tutorial is from open-source community. Access the source code
💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください
この実験では、Option
を展開するさまざまな方法を検討し、None
の場合にはデフォルト値に切り替える方法について検討します。この際、即時評価や遅延評価、空の値をそのままにするか、置き換えるかなどの要因も考慮されます。
注: 実験でファイル名が指定されていない場合、好きなファイル名を使用できます。たとえば、
main.rs
を使用して、rustc main.rs &&./main
でコンパイルして実行できます。
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でさらに多くの実験を行って練習してください。