我正在做更多的组合器 "Rust by Example"的一部分,并决定自己去看看它用了多少努力map
代替and_then
.
在我的尝试中,我遇到了一些非常奇怪的东西(它甚至看起来像编译器错误).它看起来像我只需要返回一个Food
类型时,返回类型应该是Option(Food)
在我看来,cookable
下面的功能应该可以简化为一行:
have_ingredients(food).map(|f| can_cook(f))
Run Code Online (Sandbox Code Playgroud)
显然它也可以是以下内容:
have_ingredients(food).and_then(can_cook)
Run Code Online (Sandbox Code Playgroud)
虽然我没有看到这两个函数之间的根本区别,因为它们都返回了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);
}
Run Code Online (Sandbox Code Playgroud)
以下是上述程序的完整编译器错误:
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
Run Code Online (Sandbox Code Playgroud)
have_ingredients(food).map(|f| can_cook(f))
Run Code Online (Sandbox Code Playgroud)
给出一个Option<Option<Food>>
,而不是一个Option<Food>
,因为map
不会使价值变平.
考虑
Option<T>::map(Fn(T) -> U)
Run Code Online (Sandbox Code Playgroud)
这转变Option<T>
为Option<U>
.因此,让T = Food
,U = Option<Food>
如在can_cook
实例中
Option<Food>::map(Fn(Food) -> Option<Food>)
Run Code Online (Sandbox Code Playgroud)
这给了一个Option<Option<Food>>
.
因此Some(food)
在比赛中有food
类型Option<Food>
.
and_then
展平结果类型,这就是为什么不会出现这种情况.
归档时间: |
|
查看次数: |
68 次 |
最近记录: |