Rustのエラーハンドリング
結局どう書けばいい?
Rustのエラーハンドリングは過渡期でベストプラクティスはないらしい。とはいえ、どう書くかを選択する必要がある。
参考文献
- https://cha-shu00.hatenablog.com/entry/2020/12/08/060000
- zero2prod
- rust for rustaceans
- https://blog.rust-lang.org/inside-rust/2021/07/01/What-the-error-handling-project-group-is-working-towards.html
TODO
- anyhowとthiserrorについての理解を深める
- RustConf 2020: Error Handing Isn't All About Errors視聴する
Enumeration
自前でラップ
pub enum CopyError {
In(std::io::Error),
Out(std::io::Error),
}
やるべきこと
-
std::io::Error
トレイトを実装する。 -
Display
とDebug
を実装する。-
Display
何を誤ったかの一行の描写 小文字 句読点なし
-
-
Debug
より説明的なエラー - (可能なら)
Send
とSync
を実装する。 - (可能なら)
'static
にする。
Erasure
Box化
type erased error
Box<dyn Error + Send + Sync + 'static>
Errorトレイト
pub trait Error: Debug + Display {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
Result
で必要とされているように見えるが実はそうではない。
pub enum Result<T, E> {
Ok(T),
Err(E),
}
じゃあError
トレイトの使いみちは?
→意味的にこれがエラーであるとマークすること。
良いエラーとは
- 異なった表現(
Debug
とDisplay
)を実装すること、異なった慣習に合わせて。 - 下に横たわるエラーを見ることを可能にすること。
source
メソッドの目的はerror chainに深く潜ること。
エラーハンドリングの明日
現在の問題
現在のコンテキストをうっかりで失ってしまうことが容易。
失いうる場所
- エラーをプリントするとき
source
をプリントするのを忘れる。 -
main
からエラーを戻す時 - 回復可能なエラーを回復不可能なエラーに変換するとき
問題点
unwrap
とexpect
はDebug
implを使ってエラーを文字列化する。が
その過程でError
トレイトによって注意深く分割されたコンテキストの断片を失っていしまう。
Rustのパニック機構をError
型をパニックに変換する機構を持っていない。←これが主要な問題だと思っている。
今日の(間に合せの?)解決策
Debug
トレイトを悪用すること。= Debug
のアウトプットが人間が読める形でエラーチェーン全体をプリントするようにする。 eyre
やanyhow
がやっていること。
ただし、この方法では派生した我々のエラーのDebug
形式にアクセスできない。デバッグに必要な内部の詳細が隠される可能性があるが、これはユーザが読むことを目的としてエラーメッセージの一部ではない。
独自のエラー構造体を実装してenumでまとめてFrom
トレイトを実装するメリットは?
エラーごとに独自のの情報を保持できる
疑問
anyhow::Resultは人のエラー型に対してFromを実装している?
box化されたエラー型から具体的な値を取得する方法は存在する? downcast
単一種類のエラーを返す場合
好きにすれば良いがエラー型は実装しといた方が良い。なぜなら?でボックス化されたエラーに変換できる
複数種類のエラーを返す場合
enumかbox
具体的なエラー型を使ってなにかしたい場合等はenum パターンマッチで取れる
レポートするだけならbox
eyreも調べる。
thiserrorとanyhowは程々に。
this error
error display from