Rustでのエラーハンドリング
34日連続で雨だったそうで、そりゃー今年は涼しかったわけですね。その分千葉のあたりは大変なことになっておりますが。 Rustで真面目にWeb APIを作っていると、とても悩ましいのがエラーハンドリングだと思います。ちょっとやってみた内容を紹介します。 Result or panic これについては、Javaとか他の言語のノリでpanicすると大変なことになるので、まず 原則panic禁止 くらいでいいかと思います。CLIならpanicしたほうがいいケースも多いと思いますが、Web APIでやったら多分ぶっ殺されます。 panic自体はhandlerがあったりはしますが、それに頼ったところでrewindとかそういったものもないので、SpringBootとかの黒魔術に慣れた人は、わりと気をつける必要があります(自分)。 anyhow/eyreで潰す or 潰さない エラーハンドリングを語るときに外せない eyreまたは anyhow がまず出てくると思います。これは Box<dyn std::error::Error + Sync + Send + 'static> あたりを都度定義する・・・というところに対するカウンターだと理解してます。 これが効果を発揮するのは、 とりあえずResultにするけど、エラー定義がめんどくせぇ ってときだと思います。基本的に eyre! などで潰すことで、なんでも放り込めるエラーを作れます。これはプロトタイピングとか、 APIのトップレベル みたいな、もうハンドリングする必要がないところでは役立ちます。 が、これはTraitでは使えません。というか使うと困るのは多分自分です :angel: pub trait Hoge { // うーん、失敗するんだろうけどどう失敗するかわかんないな。とりあえず潰しとこう fn foobar() -> eyre::Result<Huga>; } fn main() { let foo = Foo::new(); foo.foobar().map_err(|e| { match e { // さて・・・?あれ、区別できないぞ } }) } traitはinterfaceというか操作の契約=contractを表すので、エラーになるのであれば、きちんと定義しておくのがベターであるとは思います。今のところはこのように整理しました。 Trait境界ではeyre/anyhowを 使わない eyre/anyhowはmainとかでは使ってよし どうせpanicするレベルなので DDDとかでドメイン層がある場合は・・・後述 みんなの味方、thiserror thiserror は、おそらくエラーを定義する際にはほぼ必携のcrateです。手で書くとひっじょーにめんどくさいError traitの実装を肩代わりしてくれるのとともに、color_eyreを利用したときに役立つsource chainのハンドリングもしてくれます。 ...