2024-04-13. PDF
enum Result<T, E> {
Ok(T),
Err(E),
}
fn is_ok(&self) -> bool;
fn is_err(&self) -> bool;
fn unwrap(self) -> T;
fn unwrap_err(self) -> E;
fn map(&self, op: F) -> Result<U, E>
where F: FnOnce(T) -> U;
fn write_message() -> io::Result<()> {
// ? 表示如果出错,立刻返回
let mut file = File::create("valuable_data.txt")?;
file.write_all(b"important message")?;
Ok(())
}
match write_message() {
Ok(happy) => println!("😄"),
Err(sad) => {
eprintln!("🥶");
return;
}
}
pub trait Error: Debug + Display {
fn source(&self) -> Option<&(dyn Error + 'static)>;
...
}
// 处理 error 链
fn print_error(mut error: &dyn Error) {
println!("Got an error:{:?}", error.to_string());
while let Some(cause) = error.source() {
println!("Caused by: {}", cause);
error = cause;
}
}
Exception
try {
v1 = get_from_db();
v2 = prepare(v1);
v3 = render(v2);
} catch (ex) {
// handle ex
}
Result
v1 = get_from_db()?;
v2 = prepare(v1)?;
v3 = render(v2)?;
提供 anyhow::Error 类型,相比 StdError
From<Error> for StdErrorfn read_file() -> anyhow::Result<String> {
let body = std::fs::read_to_string("input.txt")
.context("read input.txt failed")?;
Ok(body)
}
if let Err(err) = read_file() {
println!("{:?}", err);
}
read input.txt failed
Caused by:
No such file or directory (os error 2)
RUST_BACKTRACE=1 cargo run
Caused by:
No such file or directory (os error 2)
Stack backtrace:
2: std::backtrace::Backtrace::create
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/backtrace.rs:331:13
3: <E as anyhow::context::ext::StdError>::ext_context
at /Users/jiacai/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/anyhow-1.0.82/src/context.rs:27:29
4: anyhow::context::<impl anyhow::Context<T,E> for core::result::Result<T,E>>::context
at /Users/jiacai/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/anyhow-1.0.82/src/context.rs:54:31
5: anyhow::read_file
at ./src/anyhow_demo.rs:8:16
6: anyhow::main
at ./src/anyhow_demo.rs:53:21
#[derive(Error, Debug)]
pub enum MyError {
#[error("data store disconnected")]
Io(#[from] io::Error),
#[error("Unxpected error, `{0}`.")]
Unexpected(String),
#[error("unknown error")]
Unknown,
}
pub fn read_file() -> Result<String, MyError> {
let body = std::fs::read_to_string("input.txt")?;
Ok(body)
}
类似于相当于 anyhow 与 thiserror 的结合体
提供 Whatever 错误类型,简化处理
fn read_file(path: &str) -> Result<String, Whatever> {
std::fs::read_to_string(path)
.with_whatever_context(|_| format!("Could not read file {path}"))
}
#[derive(Snafu, Debug)]
pub enum MyError {
#[snafu(display("Io error, {source}"))]
Io { source: std::io::Error },
#[snafu(display("Unxpected error, msg:{msg}."))]
Unexpected { msg: String },
#[snafu(display("Unknown error"))]
Unknown,
}
pub fn read_file() -> Result<String> {
let body = read_to_string("input.txt").context(IoSnafu {})?;
Ok(body)
}
错误会被怎么使用?
显示给用户(Binary)
使用者不会检查 fmt::Display 以外的错误信息,因此可以封装其内部结构
pub enum Error {
Tokio(tokio::io::Error),
ConnectionDiscovery {
path: PathBuf,
reason: String,
stderr: String,
},
Deserialize {
source: serde_json::Error,
data: String,
},
...,
Generic(String),
}
可能有的问题?
std.io.Error
pub struct Error {
repr: Repr,
}
enum Repr {
Os(i32),
Simple(ErrorKind),
Custom(Box<Custom>),
}
struct Custom {
kind: ErrorKind,
error: Box<dyn error::Error + Send + Sync>,
}
#[derive(Clone, Copy)]
#[non_exhaustive]
pub enum ErrorKind {
NotFound,
PermissionDenied,
Other,
}
impl Error {
pub fn kind(&self) -> ErrorKind {
match &self.repr {
Repr::Os(code) => sys::decode_error_kind(*code),
Repr::Custom(c) => c.kind,
Repr::Simple(kind) => *kind,
}
}
}
| anyhow | 👍 |
| thiserror | 👍 |
| snafu | 👎 |
Q & A