Option & unwrap

在最后一个例子中,我们展示了我们可以随意地引发程序失败。我们告诉我们的程序,如果我们喝了含糖的柠檬水,就 panic。但是如果我们期望得到某种饮料但没有收到呢?这种情况同样糟糕,所以需要处理!

我们可以像处理柠檬水一样,用空字符串 ("") 来测试这种情况。既然我们使用的是 Rust,那就让编译器指出没有饮料的情况吧。

当缺失成为一种可能性时,会使用 std 库中的一个名为 Option<T>enum。它表现为以下两种“选项”之一:

  • Some(T): 找到了 T 类型的一个元素
  • None: 没有找到元素

这些情况可以通过 match 显式处理,也可以通过 unwrap 隐式处理。隐式处理要么返回内部元素,要么 panic

请注意,可以使用 expect 手动自定义 panic,但 unwrap 否则会给我们留下一个不如显式处理有意义的输出。在下面的例子中,显式处理会产生更受控制的结果,同时保留在需要时 panic 的选项。

// The adult has seen it all, and can handle any drink well.
// All drinks are handled explicitly using `match`.
fn give_adult(drink: Option<&str>) {
    // Specify a course of action for each case.
    match drink {
        Some("lemonade") => println!("Yuck! Too sugary."),
        Some(inner)   => println!("{}? How nice.", inner),
        None          => println!("No drink? Oh well."),
    }
}

// Others will `panic` before drinking sugary drinks.
// All drinks are handled implicitly using `unwrap`.
fn drink(drink: Option<&str>) {
    // `unwrap` returns a `panic` when it receives a `None`.
    let inside = drink.unwrap();
    if inside == "lemonade" { panic!("AAAaaaaa!!!!"); }

    println!("I love {}s!!!!!", inside);
}

fn main() {
    let water  = Some("water");
    let lemonade = Some("lemonade");
    let void  = None;

    give_adult(water);
    give_adult(lemonade);
    give_adult(void);

    let coffee = Some("coffee");
    let nothing = None;

    drink(coffee);
    drink(nothing);
}