解包选项和默认值
有多种方法可以解包 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` moves its argument. // In the example above, `or(orange)` returned a `Some`, so `or(apple)` was not invoked. // But the variable named `apple` has been moved regardless, and cannot be used anymore. // println!("Variable apple was moved, so this line won't compile: {:?}", apple); // TODO: uncomment the line above to see the compiler error }
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!("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: uncomment the line above to see the compiler error }
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) // If the Option has a value, it is left unchanged, and the closure is not invoked 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); // The output is a follows. Note that the closure `get_lemon_as_fallback` is not invoked // should_be_apple is: Apple // my_apple is unchanged: Some(Apple) }