我正在执行“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
答案 0 :(得分:6)
Option<Option<Food>>
提供Option<Food>
,而不是map
,因为Option<T>::map(Fn(T) -> U)
没有展平价值。
考虑
Option<T>
这会将Option<U>
转换为T = Food
。因此,让U = Option<Food>
,can_cook
与Option<Food>::map(Fn(Food) -> Option<Food>)
一样,实例化
Option<Option<Food>>
给出Some(food)
。
因此,匹配中的food
的{{1}}类型为Option<Food>
。
and_then
会使结果类型变平,这就是为什么不会出现这种情况。