Slide 1

Slide 1 text

anyhowの簡単な使い方 dalance

Slide 2

Slide 2 text

自己紹介 ● 名前:初田 直也 ● Githubアカウント:dalance ● 所属:株式会社PEZY Computing ● 業務:プロセッサLSI開発 PEZY-SC2

Slide 3

Slide 3 text

anyhowとは ● アプリケーション用のエラーライブラリの一つ ○ ライブラリのエラーはスコープ外 ● 次世代のデファクトスタンダードになる可能性が高そう ○ 標準ライブラリのErrorトレイトを実装している ■ 現行デファクトのfailureはそうではない ○ cargoの実装にも使われている ○ 最近急激にシェアを伸ばしている

Slide 4

Slide 4 text

なぜエラーライブラリを使うか? ● 例えば簡単なTOML表示アプリを考える ○ まずはエラー処理なしで fn main() { let content = std::fs::read("Cargo.toml").unwrap(); let content = String::from_utf8(content).unwrap(); let value = content.parse::().unwrap(); dbg!(value); }

Slide 5

Slide 5 text

エラー処理を追加してみる ● mainからエラーを返すようにする ○ エラーの可能性がある場合は Resultで返す ○ 戻り値がOkなら正常、Errならエラー fn main() -> Result<(), std::io::Error> { let content = std::fs::read("Cargo.toml"); // readはResult, std::io::Error>を返す let content = match content { Ok(x) => x, Err(x) => return Err(x), }; let content = String::from_utf8(content).unwrap(); let value = content.parse::().unwrap(); dbg!(value); Ok(()) }

Slide 6

Slide 6 text

?演算子を使う ● ?演算子を使うと ○ Okなら、その中身を返す ○ Errならearly return fn main() -> Result<(), std::io::Error> { let content = std::fs::read("Cargo.toml")?; // この?で前のページと同じ動作 let content = String::from_utf8(content).unwrap(); let value = content.parse::().unwrap(); dbg!(value); Ok(()) }

Slide 7

Slide 7 text

さらにエラー処理を追加 ● 次のエラーはFromUtf8Error ○ 最初のstd::io::Errorとは違うのでmainから返せない fn main() -> Result<(), std::io::Error> { let content = std::fs::read("Cargo.toml")?; let content = String::from_utf8(content)?; // `?` couldn't convert the error to `std::io::Error` let value = content.parse::()?; dbg!(value); Ok(()) }

Slide 8

Slide 8 text

mainのエラー型は何にすればよいか? ● 自分でエラー型を定義することができる ○ https://doc.rust-jp.rs/the-rust-programming-language-ja/1.9/book/error-handling.html ■ 日本語だが少し内容が古い ○ https://blog.burntsushi.net/rust-error-handling/ ■ こちらは最新 ● 一度は自分で書くと勉強になるが、毎回書くのは面倒

Slide 9

Slide 9 text

そこでanyhow ● mainのエラー型をanyhow::Errorにする ○ std::io::ErrorやFromUtf8Errorから勝手に変換してくれる fn main() -> Result<(), anyhow::Error> { let content = std::fs::read("Cargo.toml")?; let content = String::from_utf8(content)?; let value = content.parse::()?; dbg!(value); Ok(()) }

Slide 10

Slide 10 text

エラー表示はこんな感じ ● mainがエラーを返す場合、デフォルトで表示まで実装される ○ このままだと分かりにくい ○ No such file or directory って何が? fn main() -> Result<(), anyhow::Error> { let content = std::fs::read("a.toml")?; // 存在しないファイルを読んでみる let content = String::from_utf8(content)?; let value = content.parse::()?; dbg!(value); Ok(()) } Error: No such file or directory (os error 2)

Slide 11

Slide 11 text

エラー表示を改善する ● contextに追加の説明を書ける use anyhow::Context; fn main() -> Result<(), anyhow::Error> { let content = std::fs::read("a.toml").context("failed to read a.toml")?; let content = String::from_utf8(content)?; let value = content.parse::()?; dbg!(value); Ok(()) } Error: failed to read a.toml Caused by: No such file or directory (os error 2)

Slide 12

Slide 12 text

エラー表示を改善する ● 何か処理が発生するならwith_contextが良い ○ エラー時だけ処理が実行される use anyhow::Context; fn main() -> Result<(), anyhow::Error> { let content = std::fs::read("a.toml").context("failed to read a.toml")?; let content = String::from_utf8(content).context("failed to convert to UTF-8")?; let value = content .parse::() .with_context(|| format!("failed to parse as TOML:\n{}", content))?; dbg!(value); Ok(()) }

Slide 13

Slide 13 text

その他の機能 ● エラー生成やearly return用マクロ use anyhow::{anyhow, bail, ensure}; fn main() -> anyhow::Result<()> { let args = std::env::args().len(); ensure!(args > 2, "args must be more than 2"); if args > 10 { bail!("too many args"); } Err(anyhow!("quit")) }

Slide 14

Slide 14 text

まとめ ● アプリケーションのエラー型はanyhow::Errorを使うとよい ○ ただしbacktraceはstableでは使用不可 ○ backtraceが必要ならfailure::Errorがほぼ同じように使える ● ライブラリの場合は独自のエラー型をちゃんと作るべき ○ それをサポートするためのエラーライブラリもある ■ thiserror ■ failure