#derive-error #error #io-error #error-handling #macro-derive #derive

therror

带点特色的 derive(Error)(基于 thiserror)

1 个不稳定版本

0.0.48 2023年9月7日

#1299Rust 模式

MIT/Apache

30KB
332

derive(Error)

github crates.io docs.rs build status

此库提供了一个方便的 derive 宏,用于标准库的 std::error::Error 特征。

[dependencies]
thiserror = "1.0"

编译器支持:需要 rustc 1.56+


示例

use therror::Error;

#[derive(Error, Debug)]
pub enum DataStoreError {
    #[error("data store disconnected")]
    Disconnect(#[from] io::Error),
    #[error("the data for key `{0}` is not available")]
    Redaction(String),
    #[error("invalid header (expected {expected:?}, found {found:?})")]
    InvalidHeader {
        expected: String,
        found: String,
    },
    #[error("unknown data store error")]
    Unknown,
}

详细信息

  • Thiserror 故意不出现在你的公共 API 中。你得到的结果就像你手动编写了 std::error::Error 的实现一样,并且从手动编写 impl 切换到 thiserror 或反之亦然不会造成破坏性变更。

  • 错误可以是枚举、具有命名字段的 struct、元组 struct 或单元 struct。

  • 如果你在 struct 或枚举的每个变体上提供了 #[error)("...")] 消息,则会为你的错误生成一个 Display 实现,如示例中所示。

    这些消息支持从错误中插值字段的简写。

    • #[error)("{"var"}")write!("{}", self.var)
    • #[error("{0}")] ⟶ write!("{}", self.0)
    • #[error("{var:?}")] ⟶ write!("{:?}", self.var)
    • #[error("{0:?}")] ⟶ write!("{:?}", self.0)

    这些缩写可以与任何附加格式参数一起使用,这些参数可以是任意表达式。例如

    #[derive(Error, Debug)]
    pub enum Error {
        #[error("invalid rdo_lookahead_frames {0} (expected < {})", i32::MAX)]
        InvalidLookahead(u32),
    }
    

    如果其中一个附加表达式参数需要引用结构体或枚举的字段,那么可以按 .var 引用命名字段,按 .0 引用元组字段。

    #[derive(Error, Debug)]
    pub enum Error {
        #[error("first letter must be lowercase but was {:?}", first_char(.0))]
        WrongCase(String),
        #[error("invalid index {idx}, expected at least {} and at most {}", .limits.lo, .limits.hi)]
        OutOfBounds { idx: usize, limits: Limits },
    }
    
  • 为每个包含 #[from] 属性的变体生成了一个 From 实现。

    注意,变体不得包含任何其他字段,除了源错误和可能的回溯。如果有字段为回溯,则从 From 实现中捕获回溯。

    #[derive(Error, Debug)]
    pub enum MyError {
        Io {
            #[from]
            source: io::Error,
            backtrace: Backtrace,
        },
    }
    
  • 实现了 Error trait 的 source() 方法,以返回具有 #[source] 属性或命名 source 的字段,如果有任何。这是为了确定导致您的错误的底层错误。

    #[from] 属性始终意味着相同的字段是 #[source],因此您永远不需要指定这两个属性。

    任何实现了 std::error::Error 或引用 dyn std::error::Error 的错误类型都可以作为源。

    #[derive(Error, Debug)]
    pub struct MyError {
        msg: String,
        #[source]  // optional if field name is `source`
        source: anyhow::Error,
    }
    
  • 错误特质(Error trait)的 provide() 方法被实现,用于提供任何具有名为 Backtrace 类型的字段,如果有,则作为 std::backtrace::Backtrace 的实例。

    use std::backtrace::Backtrace;
    
    #[derive(Error, Debug)]
    pub struct MyError {
        msg: String,
        backtrace: Backtrace,  // automatically detected
    }
    
  • 如果一个字段既是源(命名为 source,或具有 #[source]#[from] 属性)并且 被标记为 #[backtrace],则错误特质的 provide() 方法将转发到源的 provide 方法,以便错误的两层都能共享相同的回溯(backtrace)。

    #[derive(Error, Debug)]
    pub enum MyError {
        Io {
            #[backtrace]
            source: io::Error,
        },
    }
    
  • 错误可以使用 error(transparent) 来直接将源和显示方法转发到底层错误,而不添加额外的消息。这适用于需要“其他所有情况”变体的枚举。

    #[derive(Error, Debug)]
    pub enum MyError {
        ...
    
        #[error(transparent)]
        Other(#[from] anyhow::Error),  // source and Display delegate to anyhow::Error
    }
    

    另一个用例是在不破坏crate的公共API的情况下,隐藏错误表示的实现细节,使表示能够进化。

    // PublicError is public, but opaque and easy to keep compatible.
    #[derive(Error, Debug)]
    #[error(transparent)]
    pub struct PublicError(#[from] ErrorRepr);
    
    impl PublicError {
        // Accessors for anything we do want to expose publicly.
    }
    
    // Private and free to change across minor version of the crate.
    #[derive(Error, Debug)]
    enum ErrorRepr {
        ...
    }
    
  • 有关在应用程序代码中使用方便的单个错误类型,请参阅 anyhow 库。


与 anyhow 的比较

如果您关心设计自己的专用错误类型(s),以便在失败时调用者接收您选择的确切信息,请使用 therror。这通常适用于类似库的代码。如果您不关心函数返回的错误类型,只是希望操作简单,请使用 Anyhow。这在类似应用程序的代码中很常见。


thiserror 的分支

这个分支是为了给 thiserror 添加一个杀手特性而创建的,这个特性肯定不会进入 thiserror 本身。我们将一旦有更多想法就继续写。

许可证

根据您的选择,在 Apache License, Version 2.0MIT license 许可下进行许可。
除非您明确声明,否则根据 Apache-2.0 许可证定义的,您提交给此crate的任何有意贡献,都将根据上述许可双重许可,没有任何额外条款或条件。

依赖关系

~295–750KB
~18K SLoC