推導錯誤列舉

thiserror crate 很常用來建立錯誤列舉,我們在上一頁就曾這麼做:

use std::{fs, io};
use std::io::Read;
use thiserror::Error;

#[derive(Debug, Error)]
enum ReadUsernameError {
    #[error("Could not read: {0}")]
    IoError(#[from] io::Error),
    #[error("Found no username in {0}")]
    EmptyUsername(String),
}

fn read_username(path: &str) -> Result<String, ReadUsernameError> {
    let mut username = String::new();
    fs::File::open(path)?.read_to_string(&mut username)?;
    if username.is_empty() {
        return Err(ReadUsernameError::EmptyUsername(String::from(path)));
    }
    Ok(username)
}

fn main() {
    //fs::write("config.dat", "").unwrap();
    match read_username("config.dat") {
        Ok(username) => println!("Username: {username}"),
        Err(err)     => println!("Error: {err}"),
    }
}

thiserror 的衍生巨集會自動實作 std::error::Error,並視情況實作 Display (如果提供了 #[error(...)] 屬性的話) 和 From (如果新增了 #[from] 屬性的話)。上述原則也適用於結構體。

這個不會影響你的公用API,因此這對程式庫很好。