Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Shinjuku.rs #8 dalance

dalance
January 21, 2020

Shinjuku.rs #8 dalance

dalance

January 21, 2020
Tweet

More Decks by dalance

Other Decks in Programming

Transcript

  1. anyhowの簡単な使い方 dalance

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

    PEZY-SC2
  3. anyhowとは • アプリケーション用のエラーライブラリの一つ ◦ ライブラリのエラーはスコープ外 • 次世代のデファクトスタンダードになる可能性が高そう ◦ 標準ライブラリのErrorトレイトを実装している ▪

    現行デファクトのfailureはそうではない ◦ cargoの実装にも使われている ◦ 最近急激にシェアを伸ばしている
  4. なぜエラーライブラリを使うか? • 例えば簡単なTOML表示アプリを考える ◦ まずはエラー処理なしで fn main() { let content

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

    main() -> Result<(), std::io::Error> { let content = std::fs::read("Cargo.toml"); // readはResult<Vec<u8>, 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::<toml::Value>().unwrap(); dbg!(value); Ok(()) }
  6. ?演算子を使う • ?演算子を使うと ◦ 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::<toml::Value>().unwrap(); dbg!(value); Ok(()) }
  7. さらにエラー処理を追加 • 次のエラーは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::<toml::Value>()?; dbg!(value); Ok(()) }
  8. mainのエラー型は何にすればよいか? • 自分でエラー型を定義することができる ◦ https://doc.rust-jp.rs/the-rust-programming-language-ja/1.9/book/error-handling.html ▪ 日本語だが少し内容が古い ◦ https://blog.burntsushi.net/rust-error-handling/ ▪

    こちらは最新 • 一度は自分で書くと勉強になるが、毎回書くのは面倒
  9. そこで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::<toml::Value>()?; dbg!(value); Ok(()) }
  10. エラー表示はこんな感じ • 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::<toml::Value>()?; dbg!(value); Ok(()) } Error: No such file or directory (os error 2)
  11. エラー表示を改善する • 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::<toml::Value>()?; dbg!(value); Ok(()) } Error: failed to read a.toml Caused by: No such file or directory (os error 2)
  12. エラー表示を改善する • 何か処理が発生するなら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::<toml::Value>() .with_context(|| format!("failed to parse as TOML:\n{}", content))?; dbg!(value); Ok(()) }
  13. その他の機能 • エラー生成や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")) }
  14. まとめ • アプリケーションのエラー型はanyhow::Errorを使うとよい ◦ ただしbacktraceはstableでは使用不可 ◦ backtraceが必要ならfailure::Errorがほぼ同じように使える • ライブラリの場合は独自のエラー型をちゃんと作るべき ◦

    それをサポートするためのエラーライブラリもある ▪ thiserror ▪ failure