わかりやすいエラー メッセージを表示する
今のところ、存在しないジャーナル ファイルから読み取ろうとすると、プログラムはパニックになり、次のように出力されます。
$ cargo run -- done 2
thread 'main' panicked at 'Failed to perform action: Os { code: 2, kind: NotFound, message: "No such file or directory" }'
このエラーは、ユーザーにとってはやや冗長なので、よりわかりやすくする必要があります。 そのタスクを処理する大量のコードを書くこともできますが、anyhow
という、有用で適切なエラーをユーザーに表示できる優れたクレートがあります。
anyhow
クレートの背後にあるロジックは、独自のエラーの種類を提供することです。 この種類には整形出力のプロパティがあり、std::io::Error
などの他のエラーから簡単に変換できます。 anyhow
をプロジェクトに追加するのは簡単です。 main
関数の戻り値の型として配置するだけです。
まず、Cargo.toml
ファイルで宣言します。
[dependencies]
anyhow = "1.0" # <--- Add `anyhow` to our project dependencies.
home = "0.5"
serde_json = "1.0"
structopt = "0.3"
[dependencies.chrono]
features = ["serde"]
version = "0.4"
[dependencies.serde]
features = ["derive"]
version = "1.0"
次に、型 anyhow::Result<()>
を返すように main
関数のシグネチャを更新します。
use anyhow::anyhow;
use std::path::PathBuf;
use structopt::StructOpt;
mod cli;
mod tasks;
use cli::{Action::*, CommandLineArgs};
use tasks::Task;
fn find_default_journal_file() -> Option<PathBuf> {
home::home_dir().map(|mut path| {
path.push(".rust-journal.json");
path
})
}
fn main() -> anyhow::Result<()> {
let CommandLineArgs {
action,
journal_file,
} = CommandLineArgs::from_args();
let journal_file = journal_file
.or_else(find_default_journal_file)
.ok_or(anyhow!("Failed to find journal file."))?;
match action {
Add { task } => tasks::add_task(journal_file, Task::new(task)),
List => tasks::list_tasks(journal_file),
Done { position } => tasks::complete_task(journal_file, position),
}?;
Ok(())
}
ほとんどのエラーの種類は anyhow::Error
に変換できるので、?
構文を使用してコードから expect
の呼び出しを削除できます。 また、anyhow!
マクロを使用して、指定されたエラー メッセージを含む anyhow::Error
をその場で生成している点を確認してください。
これで、プログラム内から返される I/O エラーが原因で発生するすべてのパニック メッセージが、次のようにユーザーに表示されます。
$ cargo run -- -j missing-journal done 2
Error: No such file or directory (os error 2)
数行のコードを追加しただけにしては、かなりの改善です。