標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

Rust で panic なしに雑にエラーを扱いたいとき

Go だと、errors.New, fmt.Errorf で、簡単にエラーオブジェクトを作れる。

Rust のエラー処理のサンプルをいろいろ見てみたが、panic で終わらせるものが多いが、panic を使った時点で関数の汎用性がほとんどなくなってしまう。

エラーを返す場合、ほとんどの記事では自前のエラー型を作らせているが、手間がかかりすぎる。簡略化するクレートとしては、 anyhow 、thiserror などがよく紹介されているが1、 errors.New , fmt.Errorf に比べると、それすら大仰すぎる。

さらにずぼらなエラー処理を模索すると、無いこともないようで、次のような方法が見受けられた。

  1. Result<…,String> のように文字列型をエラーにしてしまう
  2. Result<…,Box<dyn std::error:Error>> を使う

前者の場合、同じ関数内で ? 演算子が使えなくなってしまうため、後者を取ると、

  • 既存のエラーオブジェクトは、そのまま ? で return 値にできる(同じ trait なので)
  • errors.New, fmt.Errorf 的な簡易エラーは return Err(Box::from("…")) で作成

という形になる。これで、拙作の sponge のmain関数を書き直してみた。

fn mains() -> Result<(), Box<dyn std::error::Error>> {
    let mut args = std::env::args().skip(1);
    let original = match args.next() {
        Some(original) => original,
        None => return Err(Box::from("filename is not specified")),
    };
    sponge(&original)?;
    Ok(())
}

fn main() {
    if let Err(err) = mains() {
        eprintln!("{}", err);
        std::process::exit(1);
    }
}

よしよし