rust 有没有一种方法可以在没有map_err的情况下对不同的错误类型使用and_then?

2o7dmzc5  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(113)

我有一些函数在失败时会返回不同的错误类型。
首先,我有一个构建器,它包含这个方法:

#[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>

这个想法是我使用构建器创建一个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来从BuilderErrorXmlError转换为WebserviceError
我的问题是,我能做得更好吗?我认为这样的解决方案是理想的:

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

kadbb4591#

经过一些尝试,以下是解决方案:

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函数,该函数将在其中进行转换,从而清除代码

bnlyeluc

bnlyeluc2#

如果你真的对精确的错误不感兴趣,但在最后提出一些最终的错误,你可以使用这样的东西:

builder.spawn().ok()
    .and_then(|v| status.create_xml(v).ok())
    .ok_or_else(|| SomeError('failed to create xml'))

相关问题