🐈
anyhowでRustのエラーハンドリングメモ
(どうやらanyhowクレートを使うと簡単にエラーハンドリングできるらしい)
(Stringとstd系Errorの狭間で考えていた時間は徒労に終わった)
anyhowクレートとは
エラーハンドリング用のクレート(これ)です。
↓の記事がわかりやすかったのでこの記事だけでいいと思います。
使い方まとめ
自分用備忘リファレンスコードです。
use anyhow::{Result, Context, anyhow, bail, ensure};
fn main() -> Result<()> {
err_handle_w_anyhow(&0)?;
Ok(())
}
fn err_handle_w_anyhow(handle_type: &i32) -> Result<()> {
let foo = "foo";
let mut misc: Vec<String> = Vec::new();
let conditional_expr = false;
match *handle_type {
1 => std::fs::read_to_string(foo).context("anyhow::Error is created with io::Error and this strings.")?,
2 => std::fs::read_to_string(foo).with_context(|| format!("To avoid format cost etc., lazy eval is abled. {}", foo))?,
3 => misc.pop().context("Option::None is casted to Result::Err.")?,
_ => String::default(),
};
match *handle_type {
4 => { return Err(anyhow!("Create anyhow::Error by manual like format: {}", foo)); },
5 => { bail!("bail!({}) == return Err(anyhow!({}))", foo, foo); },
6 => { ensure!(conditional_expr, "If conditional expr is false, bail!({})", foo); },
_ => (),
};
Ok(())
}
// test with the command: cargo test -- --nocapture
#[cfg(test)]
mod tests{
use crate::err_handle_w_anyhow;
#[test]
fn test_run() {
for i in 1..7 {
println!("---------- pattern {} ----------", i);
if let Err(e) = err_handle_w_anyhow(&i) {
println!("{:?}", e);
}
}
}
}
テスト結果
vscode ➜ /workspaces/z_rust_sandbox (master) $ cargo test -- --nocapture
Compiling z_rust_sandbox v0.1.0 (/workspaces/z_rust_sandbox)
Finished test [unoptimized + debuginfo] target(s) in 0.17s
Running unittests src/main.rs (target/debug/deps/z_rust_sandbox-9dcf870a13e0264d)
running 1 test
---------- pattern 1 ----------
anyhow::Error is created with io::Error and this strings.
Caused by:
No such file or directory (os error 2)
---------- pattern 2 ----------
To avoid format cost etc., lazy eval is abled: foo
Caused by:
No such file or directory (os error 2)
---------- pattern 3 ----------
Option::None is casted to Result::Err.
---------- pattern 4 ----------
Create anyhow::Error by manual like format: foo
---------- pattern 5 ----------
bail!(foo) == return Err(anyhow!(foo))
---------- pattern 6 ----------
If conditional expr is false, bail!(foo)
test tests::test_run ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
所感
今のところRustのエラーハンドリングのベストプラクティスは無い?ようですが、小規模アプリでResult<T, E>
のEを何にすべきかとかスマートにエラーハンドリングうんぬん迷ったらanyhowで良さそうです。ライブラリの場合はthiserrorクレートを使うらしいです。
Discussion