2017-05-04 57 views
2

我有一些函數會在失敗時返回不同的錯誤類型。在不使用map_err的情況下使用帶有不同結果錯誤類型的and_then

首先我有一個生成器,它包含以下方法:

#[derive(Debug)] 
pub enum BuilderError { 
    ElementMissing(&'static str), 
} 

pub fn spawn(self) -> Result<ServiceStatus, BuilderError> 

所以它會在失敗時返回一個BuildError。

現在,我有另一個函數將返回另一個錯誤:

#[derive(Debug)] 
pub enum XmlError { 
    XmlCreationFailed(writer::Error), 
    ConversionToUtf8(FromUtf8Error), 
} 

pub fn create_xml(service_status: super::ServiceStatus) -> Result<String, XmlError> 

的想法是,我用的是Builder創建一個ServiceStatus對象,並用它來創建create_xml功能的XML字符串。

爲了做到這一點,我有這樣的代碼:

#[derive(Debug)] 
pub enum WebserviceError { 
    XmlError(XmlError), 
    BuilderError(BuilderError), 
} 

impl std::error::Error for WebserviceError { 
    ... 
} 

impl From<XmlError> for WebserviceError { 
    fn from(error: XmlError) -> WebserviceError { 
     WebserviceError::XmlError(error) 
    } 
} 

impl From<BuilderError> for WebserviceError { 
    fn from(error: BuilderError) -> WebserviceError { 
     WebserviceError::BuilderError(error) 
    } 
} 

fn test() -> Result<String, status::WebserviceError> { 
    ... 
    let service_status = builder.spawn()?; 
    let xml = status::create_xml(service_status)?; 
    Ok(xml) 
} 

現在,我想我可以做的更好使用and_then而不是使用?運營商:

fn test() -> Result<String, status::WebserviceError> { 
    ... 
    builder 
     .spawn() 
     .map_err(status::WebserviceError::BuilderError) 
     .and_then(|hue| status::create_xml(hue).map_err(status::WebserviceError::XmlError)) 
} 

這種解決方案也是如此,但現在我需要顯式調用map_err從BuilderError或XmlError轉換爲WebserviceError ...

所以,我的問題是,我可以做的更好?我覺得像這樣的解決方案將是理想的:

fn test() -> Result<String, status::WebserviceError> { 
    ... 
    builder 
     .spawn() 
     .and_then(status::create_xml) 
} 

感謝

+0

我認爲你可以做'.map_err(Into :: into)'讓rustc找出哪個impl適用。但我更喜歡用'?'來解決這個問題 – trentcl

回答

3

一些庭審結束後,這裏是解決方案:

trait CustomAndThen<T, E> { 
    fn and_then2<U, E2, F: FnOnce(T) -> Result<U, E2>>(self, op: F) -> Result<U, E> 
     where E: std::convert::From<E2>; 
} 

impl<T, E> CustomAndThen<T, E> for Result<T, E> { 
    fn and_then2<U, E2, F: FnOnce(T) -> Result<U, E2>>(self, op: F) -> Result<U, E> 
     where E: std::convert::From<E2> 
    { 
     match self { 
      Ok(t) => op(t).map_err(From::from), 
      Err(e) => Err(e), 
     } 
    } 
} 

... 

Ok(builder) 
    .and_then2(status::ServiceStatusBuilder::spawn) 
    .and_then2(status::create_xml) 

這將爲Result類型的定製and_then功能,將使其內的轉換,清除代碼

相關問題