2016-01-23 64 views
3

我正在做「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 

回答

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

給出了一個Option<Option<Food>>,而不是一個Option<Food>,由於map不會變平值。

考慮

Option<T>::map(Fn(T) -> U) 

這種轉變Option<T>Option<U>。從而讓T = FoodU = Option<Food>can_cook給出了實例

Option<Food>::map(Fn(Food) -> Option<Food>) 

其給出一個Option<Option<Food>>

因此在比賽中Some(food)food類型Option<Food>

and_then變平結果類型,這就是爲什麼它不會發生。

+0

我現在明白了。首先,編譯器錯誤是說它期望* first *食物是食物類型。其次,映射的目的是讓你寫一個簡短的閉包,它不需要你寫一些(T)。 – vitiral

相關問題