返回选项时有些不需要吗?

时间:2016-01-23 21:05:08

标签: rust

我正在执行“Rust by Example”的more combinators部分,并决定自行离开,看看使用map代替and_then付出了多少努力。

在我的尝试中,我遇到了一些非常奇怪的东西(它甚至看起来像编译器错误)。 看起来像当返回类型应为Food时,我只需要返回Option(Food)类型

在我看来,下面的cookable功能应该可以简化为一行:

have_ingredients(food).map(|f| can_cook(f))

显然它也可以是以下内容:

have_ingredients(food).and_then(can_cook)

虽然我没有看到这两个函数之间的根本区别,因为它们都返回Option<U>

这样做时我遇到了一个奇怪的编译器错误,所以我明确地将匹配分解如下 - 看起来编译器想要返回Food,即使返回类型是Some(Food)。发生了什么???

//! stack.rs
#[derive(Debug)]
enum Food {
    CordonBleu,
    Steak,
    Sushi,
}

#[derive(Debug)]
enum Day {
    Monday,
    Tuesday,
    Wednesday,
}

/// we don't have the ingredients for sushi
fn have_ingredients(food: Food) -> Option<Food> {
    match food {
        Food::Sushi => None,
        _ => Some(food),
    }
}

/// can cook anything but cordon blue
fn can_cook(food: Food) -> Option<Food> {
    match food {
        Food::CordonBlue => None,
        _ => Some(food),
    }
}

/// can be done using map
fn cookable(food: Food) -> Option<Food> {
    match have_ingredients(food).map(|f| can_cook(f)) {
        // Some(food) => food,  // Why is this correct???
        Some(food) => Some(food), // **error: mismatched types:
        None => None,
    }
}

fn eat(food: Food, day: Day) {
    match cookable(food) {
        Some(food) => println!("Yay! On {:?} we eat {:?}", day, food),
        None => println!("Oh no we didn't get to eat on {:?}!", day),
    };
}

fn main() {
    let (cordon_bleu, steak, sushi) = (Food::CordonBleu, Food::Steak, Food::Sushi);
    eat(cordon_bleu, Day::Monday);
    eat(steak, Day::Tuesday);
    eat(sushi, Day::Wednesday);
}

以上是上述程序中的完整编译器错误:

 ch16_errors git:(master) ✗ rustc stack.rs
stack.rs:38:28: 38:32 error: mismatched types:
 expected `Food`,
    found `core::option::Option<Food>`
(expected enum `Food`,
    found enum `core::option::Option`) [E0308]
stack.rs:38         Some(food) => Some(food),
                                       ^~~~
stack.rs:38:28: 38:32 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error

1 个答案:

答案 0 :(得分:6)

Option<Option<Food>>

提供Option<Food>,而不是map,因为Option<T>::map(Fn(T) -> U) 没有展平价值。

考虑

Option<T>

这会将Option<U>转换为T = Food。因此,让U = Option<Food>can_cookOption<Food>::map(Fn(Food) -> Option<Food>) 一样,实例化

Option<Option<Food>>

给出Some(food)

因此,匹配中的food的{​​{1}}类型为Option<Food>

and_then会使结果类型变平,这就是为什么不会出现这种情况。