Visualizzare messaggi di errore descrittivi

Completato

A questo punto, se si prova a leggere un file journal che non esiste, il programma va in panico con l'output seguente:

    $ cargo run -- done 2

    thread 'main' panicked at 'Failed to perform action: Os { code: 2, kind: NotFound, message: "No such file or directory" }'

Questo errore è un po' dettagliato per gli utenti, quindi è consigliabile renderlo più comprensibile. È possibile scrivere molto codice per gestire questa attività, ma esiste un crate perfetto per visualizzare errori utili e semplici per gli utenti. Lo strumento è chiamato anyhow.

La logica alla base del crate anyhow è che fornisce un tipo di errore specifico. Questo tipo ha proprietà di riformattazione che possono essere facilmente convertite da altri errori, ad esempio std::io::Error. È facile aggiungere anyhow al progetto. È sufficiente inserirlo come tipo restituito della funzione main.

Prima di tutto, dichiararlo nel file 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"

Aggiornare ora la firma della funzione main in modo che restituisca il tipo anyhow::Result<()>:

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 { text } => tasks::add_task(journal_file, Task::new(text)),
        List => tasks::list_tasks(journal_file),
        Done { position } => tasks::complete_task(journal_file, position),
    }?;
    Ok(())
}

Poiché la maggior parte dei tipi di errore può essere convertita in anyhow::Error, è possibile usare la sintassi ? per rimuovere le chiamate a expect dal codice. Si noti anche che si sta usando la macro anyhow! per produrre immediatamente un elemento anyhow::Error contenente il messaggio di errore specificato.

A questo punto, ogni messaggio di panico causato da un errore di I/O restituito dal programma verrà visualizzato agli utenti come segue:

    $ cargo run -- -j missing-journal done 2
    Error: No such file or directory (os error 2)

Si tratta di un notevole miglioramento per poche righe di codice aggiuntive.