$30 off During Our Annual Pro Sale. View Details »

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

    View Slide

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

    View Slide

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

    View Slide

  4. なぜエラーライブラリを使うか?
    ● 例えば簡単な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);
    }

    View Slide

  5. エラー処理を追加してみる
    ● 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(())
    }

    View Slide

  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::().unwrap();
    dbg!(value);
    Ok(())
    }

    View Slide

  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::()?;
    dbg!(value);
    Ok(())
    }

    View Slide

  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/
    ■ こちらは最新
    ● 一度は自分で書くと勉強になるが、毎回書くのは面倒

    View Slide

  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::()?;
    dbg!(value);
    Ok(())
    }

    View Slide

  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::()?;
    dbg!(value);
    Ok(())
    }
    Error: No such file or directory (os error 2)

    View Slide

  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::()?;
    dbg!(value);
    Ok(())
    }
    Error: failed to read a.toml
    Caused by:
    No such file or directory (os error 2)

    View Slide

  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::()
    .with_context(|| format!("failed to parse as TOML:\n{}", content))?;
    dbg!(value);
    Ok(())
    }

    View Slide

  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"))
    }

    View Slide

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

    View Slide