选项<T>的map_err

Ale*_*nov 5 error-handling rust

因此Result<T, E>有一个非常简洁的方法map_err,允许以功能性的方式处理错误:

use std::io::Result;
use std::error::Error;
use std::string::ToString;
use std::io;

fn init() -> Result<u32> { Ok(42) }

fn do_work(_data: u32) -> Result<()> { Err(io::Error::new(io::ErrorKind::Other, "IO Error!")) }

fn handle_error<E: Error + ToString>(error: E, message: &str) -> E {
    eprintln!("{}: {}", message, error.to_string());
    error
}

fn main() {
    let _ = init()
        .map_err(|e| handle_error(e, "Init error"))
        .and_then(do_work)
        .map_err(|e| handle_error(e, "Work error")); // "Work error: IO error"
}
Run Code Online (Sandbox Code Playgroud)

如果有相同的功能风格来处理,那就太酷了Option<T>::None

use std::io::Result;
use std::error::Error;
use std::string::ToString;
use std::io;

fn init_opt() -> Option<u32> { Some(42) }

fn do_work_opt(_data: u32) -> Option<()> { None }

fn handle_none(message: &str) {
    eprintln!("{}", message);
}

fn main() {
    let _ = init_opt()
        .map_none(|| handle_none("Init error"))
        .and_then(do_work_opt)
        .map_none(|| handle_none("Work error")); // "Work error"
}
Run Code Online (Sandbox Code Playgroud)

但我在文档中没有看到此方法的任何合适的替代品Option

可以使用这样的自定义特征来完成

trait MapNone {
    fn map_none(self, op: impl FnOnce() -> ()) -> Self;
}

impl<T> MapNone for Option<T> {
    fn map_none(self, op: impl FnOnce() -> ()) -> Self {
        if self.is_none() { op(); } 
        self
    }
}
Run Code Online (Sandbox Code Playgroud)

但我确信我错过了一些东西,并且有一些很好的方法可以通过标准库做同样的事情。

完整的游乐场

Zor*_*orf 6

该函数Option::or_else是您所提议的函数的通用形式。它不要求它的函数返回单位类型,而是返回一个Option,因此只需让它返回None来模拟您的用例即可。

fn main() {
    let _ = init_opt()
        .or_else(|| {handle_none("Init error"); None})
        .and_then(do_work_opt)
        .or_else(|| {handle_none("Work error"); None}); // "Work error"
}
Run Code Online (Sandbox Code Playgroud)

当然,现在也可以返回Some(x)而不是以不同的方式分支。

最后,or_elseandand_then还可以与 结合使用map_or_else

fn main() {
    let _ = init_opt()
      .map_or_else(|| {handle_none("Init error"); None}, do_work_opt)
      .or_else(|| {handle_none("Work error"); None}); // "Work error"
}
Run Code Online (Sandbox Code Playgroud)

此代码应执行与上面相同的操作;map_or_else分支取决于选项是否是None或包含值。