Rustのpanicを拾って中身を見る
背景・前提など
(一般的な話:)回復不能なエラーはpanicで扱う
panic! したらそれで終わりだが、panicでプロセス終了させたくないときもある 例1:Rust製のパーサをライブラリとして読み込んで大量のファイルに対して実行し動作を検証してたとき、panicで検証プログラムごと止められると困るときがあった。そういうときはpanicもエラーとして記録し次に行きたい。
外部システムに依存するテストを書いていると、テストケースごとに cleanup 関数を呼びたいケースがある
panic されるとcleanup関数が呼べず次のテストケースに影響が及んでしまう(ので、panicしたら一旦cleanupしてからもう一回同じpanicをしたい)
注:回答で、そういうケースはDropを使えと言われてる。たしかに。
方法
catch_unwindを使うと panic を拾える
クロージャを受け取り、クロージャの中の処理がpanicしたらErr, しなかったらOkが返る
Errの中身は Box<dyn Any + Send>
すべての panic をcatch する保証は無い
注:これを一般的な try-catch みたいに使おうとするのは悪手。Result を使ってください
中身を見る
ここではパニックメッセージを見たい
愚直に書く
Anyなのでdowncast_refしていくと見れる
code:rs
use std::panic;
fn main() {
let p = panic::catch_unwind(|| panic!("A wild panic appeared!"));
let err = p.unwrap_err();
println!("{:#?}", err.downcast_ref::<panic::PanicInfo>()); // None
println!("{:#?}", err.downcast_ref::<&str>()); // Some("A wild panic appeared!")
}
ユーティリティにした
code:rs
pub fn get_panic_message(cause: &Box<dyn Any + Send>) -> Option<&str> {
cause
.downcast_ref::<String>()
.map(String::as_str)
.or_else(|| cause.downcast_ref::<&'static str>().map(Deref::deref))
}
↑のようなユーティリティを提供しているクレートを2つ発見
panic_mesage crate
cool_asserts crate