2 个版本

0.1.1 2023年9月14日
0.1.0 2023年9月14日

#1087Rust 模式

MIT/Apache

15KB

throwing

此crate实现了一个#[throws(...)]宏,允许你轻松声明函数可以返回的错误。这将允许你穷举所有可能的错误。它受到Java中声明异常的启发。

#[throws(...)]宏将自动生成一个可以表示所有已声明错误的枚举,为每个变体生成From<T>实现,并将函数的返回类型更改为适当的Result<T, E>。错误类型也将有ErrorDisplayDebug的实现。

此外,它还可以为错误类型生成From<T>实现,即从具有较少变体的错误类型转换为具有更多变体的错误类型。

安装

您可以使用以下命令将此crate添加到项目中

cargo add throwing

示例

从维基百科获取关于兔子的信息

use std::io::{self, stdout, Write};
use serde::Deserialize;
use throwing::throws;

#[derive(Clone, Deserialize)]
struct Summary {
    extract: String,
}

#[throws(reqwest::Error | serde_json::Error)]
fn fetch_extract() -> String {
    let url = "https://en.wikipedia.org/api/rest_v1/page/summary/Rabbit";
    let response = reqwest::blocking::get(url)?;

    let summary = response.text()?;
    let summary: Summary = serde_json::from_str(&summary)?;

    Ok(summary.extract)
}

#[throws(reqwest::Error | serde_json::Error | io::Error | break FetchExtractError)]
fn main() {
    let extract = fetch_extract()?;
    writeln!(stdout(), "{extract}")?;

    Ok(())
}

从文件中读取整数并处理错误

use std::{fs, io, num::ParseIntError};

use throwing::throws;

#[throws(ParseIntError | io::Error)]
fn read_int_from_file(path: &str) -> i64 {
    let content = fs::read_to_string(path)?;
    let value = content.trim().parse()?;
    Ok(value)
}

fn main() {
    match read_int_from_file("file.txt") {
        Ok(number) => println!("{number}"),
        Err(ReadIntFromFileError::ParseIntError(e)) => eprintln!("Failed to parse int: {e}"),
        Err(ReadIntFromFileError::IoError(e)) => eprintln!("Failed to read file: {e}"),
    }
}

为自定义类型实现 FromStr

use std::{num::ParseIntError, str::FromStr};
use throwing::define_error;

pub struct Id(u64);

define_error!(pub type ParseIdError = ParseIntError);

impl FromStr for Id {
    type Err = ParseIdError;
    
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let value = s.parse()?;
        Ok(value)
    }
}

通过 thiserror 添加带自定义错误的整数

您可以使用thiserror轻松创建简单的错误类型。

use std::{
    io::{self, stdin, BufRead, Lines},
    num::ParseIntError,
};

use thiserror::Error;
use throwing::throws;

#[derive(Debug, Error)]
#[error("unexpected end of file")]
struct EofError;

#[derive(Debug, Error)]
#[error("addition of {0} and {1} overflows")]
struct OverflowError(i32, i32);

fn add(a: i32, b: i32) -> Result<i32, OverflowError> {
    a.checked_add(b).ok_or_else(|| OverflowError(a, b))
}

#[throws(io::Error | EofError)]
fn read_line(input: &mut Lines<impl BufRead>) -> String {
    Ok(input.next().ok_or(EofError)??)
}

#[throws(io::Error | EofError | ParseIntError | OverflowError | break ReadLineError)]
fn main() {
    let mut input = stdin().lock().lines();

    let a = read_line(&mut input)?.parse()?;
    let b = read_line(&mut input)?.parse()?;

    let result = add(a, b)?;
    println!("{result}");

    Ok(())
}

依赖关系

~275–720KB
~17K SLoC