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. なぜエラーライブラリを使うか? • 例えば簡単な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); }
  2. エラー処理を追加してみる • 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(()) }
  3. ?演算子を使う • ?演算子を使うと ◦ 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(()) }
  4. さらにエラー処理を追加 • 次のエラーは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(()) }
  5. そこで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(()) }
  6. エラー表示はこんな感じ • 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)
  7. エラー表示を改善する • 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)
  8. エラー表示を改善する • 何か処理が発生するなら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(()) }
  9. その他の機能 • エラー生成や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")) }