エラーハンドリング構成 in 2020

元ネタ

nick.groenen.me

メモ

std::error::Errorトレイトが抱える問題

スタックトレースがとれない。

アプリケーションとライブラリとでエラーのあり方が異なる

ライブラリにおけるエラー
  • 意味のあるエラーを返す必要がある
  • ライブラリ内で発生したエラーはライブラリ用にラッピングされるべきである
  • ライブラリで定義されるエラーの変更は注意深くあるべきである
アプリケーションにおけるエラー
  • エラーを消費する側である
  • ユーザーへのエラー表示を考える
  • エラーの解析と検証ができるようにする

エラーハンドリングクレート 2選

作者が同一。

thiserror

エラーを定義することが出来る。

use thiserror::Error;

/// WordCountError enumerates all possible errors returned by this library.
#[derive(Error, Debug)]
pub enum WordCountError {
    /// Represents an empty source. For example, an empty text file being given
    /// as input to `count_words()`.
    #[error("Source contains no data")]
    EmptySource,

    /// Represents a failure to read from input.
    #[error("Read error")]
    ReadError { source: std::io::Error },

    /// Represents all other cases of `std::io::Error`.
    #[error(transparent)]
    IOError(#[from] std::io::Error),
}

anyhow

エラーを表示することが出来る。

use anyhow::{Context, Result};

fn main() -> Result<()> {
    for filename in env::args().skip(1).collect::<Vec<String>>() {
        let mut reader = File::open(&filename).context(format!("unable to open '{}'", filename))?;
        let wordcount =
            count_words(&mut reader).context(format!("unable to count words in '{}'", filename))?;
        println!("{} {}", wordcount, filename);
    }
    Ok(())
}

ファイルが存在しなかった場合

$ cargo run --quiet -- words.txt
Error: unable to open 'words.txt'

Caused by:
    No such file or directory (os error 2)

readでエラーが発生した場合

$ cargo run --quiet -- words.txt
Error: unable to count words in 'words.txt'

Caused by:
    0: Error encountered while reading from input
    1: read: broken pipe

スタックトレースが表示される。

関連

Rust のエラーまわりの変遷 - Qiita

The ? operator for easier error handling - The Edition Guide