所以 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"
}
如果能够使用相同的函数式风格处理 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"
}
但我在 Option文档 中并没有看到任何适合替代这种方法的内容。
可以使用自定义 trait 来实现该功能,如下所示
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
}
}
但我相信我错过了某些东西,而且通过标准库也有一种漂亮的方式来实现同样的功能。
Option
有or_else
和unwrap_or_else
方法,可以更加有用地处理None
。 - user4815162342.map_none(|| {….})
可以表示为or_else(|| {...; None})
。我不确定这是否回答了你的问题,即它是否足够简洁明了。 - user4815162342