我正在做「Rust by Example」的more combinators的一部分,並決定自己動手,看看使用map
代替and_then
需要多少努力。返回Option時有些不需要?
在我的嘗試中,我遇到了一些非常奇怪的事情(它甚至看起來像是一個編譯器錯誤)。它看起來像我只需要返回一個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
我現在明白了。首先,編譯器錯誤是說它期望* first *食物是食物類型。其次,映射的目的是讓你寫一個簡短的閉包,它不需要你寫一些(T)。 – vitiral