14个版本

使用旧Rust 2015

0.11.2 2018年5月23日
0.11.0 2017年9月7日
0.10.1 2017年5月14日
0.10.0 2017年2月26日
0.1.2 2016年11月18日

#21#error-chain

Download history 2057/week @ 2024-03-14 2258/week @ 2024-03-21 2245/week @ 2024-03-28 2128/week @ 2024-04-04 3004/week @ 2024-04-11 3672/week @ 2024-04-18 2558/week @ 2024-04-25 2058/week @ 2024-05-02 3233/week @ 2024-05-09 3156/week @ 2024-05-16 3208/week @ 2024-05-23 3111/week @ 2024-05-30 3073/week @ 2024-06-06 2883/week @ 2024-06-13 2974/week @ 2024-06-20 2403/week @ 2024-06-27

11,883 每月下载量
46 个crate中使用 (4 直接)

MIT/Apache

61KB
878

https://crates.io/crates/error-chain 的宏实现

error-chain示例

#
mod other_error {
    error_chain! {}
}

error_chain! {
    types {
        Error, ErrorKind, ResultExt, Result;
    }

    links {
        Another(other_error::Error, other_error::ErrorKind) #[cfg(unix)];
    }

    foreign_links {
        Fmt(::std::fmt::Error);
        Io(::std::io::Error) #[cfg(unix)];
    }

    errors {
        InvalidToolchainName(t: String) {
            description("invalid toolchain name")
            display("invalid toolchain name: '{}'", t)
        }
    }
}

变为

#
mod other_error {
    #[derive(Debug, ErrorChain)]
    pub enum ErrorKind {
        Msg(String),
    }
}

#[derive(Debug, ErrorChain)]
pub enum ErrorKind {
    Msg(String),

    #[cfg(unix)]
    #[error_chain(link = "other_error::Error")]
    Another(other_error::ErrorKind),

    #[error_chain(foreign)]
    Fmt(::std::fmt::Error),

    #[cfg(unix)]
    #[error_chain(foreign)]
    Io(::std::io::Error),

    #[error_chain(custom)]
    #[error_chain(description = r#"|_| "invalid toolchain name""#)]
    #[error_chain(display = r#"|t| write!(f, "invalid toolchain name: '{}'", t)"#)]
    InvalidToolchainName(String),
}

error_chain!相比的明显差异是

  • ErrorKind是一个枚举而不是宏调用。
  • 错误链接是枚举的变体而不是宏内部的行。
  • 链接有显式的注解标记它们为链式/外部/自定义,而不是被分组到宏的相应部分。
  • #[cfg]之类的属性直接应用于变体,而不是需要特殊的语法。
  • descriptiondisplay被定义为作为属性值指定的函数表达式,而不是集成到宏语法中的缩写。

不那么明显的差异是

  • ErrorKind必须显式实现::std::fmt::Debug,要么自动使用#[derive]或手动单独实现。error_chain!隐式地这样做。
  • error_chain!不同,ErrorKind不需要有pub可见性。生成的ErrorResultResultExt将与ErrorKind具有相同的可见性。
  • ErrorKind可以有一个特殊的Msg(String)成员,用于将字符串转换为ErrorKinderror_chain!隐式地执行此操作。
  • error-chain不同,Msg(String)成员是可选的。如果不存在,则ErrorKindError不会实现From<String>From<&str>
  • 文档注释,由于它们实际上相当于属性,可以应用于枚举变体,而无需像error_chain!那样的特殊语法。
  • ErrorKind可以是泛型的。

枚举属性

  • #[error_chain(error= "ErrorName")]

    将生成的Error结构体的名称重写为给定的名称。如果没有提供,结构体的名称将为Error

  • #[error_chain(result_ext= "ResultExtName")]

    将生成的ResultExt特质的名称重写为给定的名称。如果没有提供,特质的名称将为ResultExt

  • #[error_chain(result= "ResultName")]

    将生成的Result类型别名的名称重写为给定的名称。如果没有提供,别名将命名为Result。如果设置为空字符串"",则不会生成该别名。

  • #[error_chain(backtrace = "false")]#[error_chain(backtrace = false)]

    在生成的代码中禁用回溯功能。这应与error-chaincrate中backtrace功能的值保持一致。换句话说,如果您在这里将backtrace = "false"设置,则还必须在您的Cargo.toml中指定default-features = false

变体定义

  • 可链接的链接

    #
    #
    #[error_chain(link = "other_error::Error")]
    Another(other_error::ErrorKind),
    

    可链接的链接是使用error-chainderive-error-chain生成的错误和errorkind。变体必须有一个字段来保存链式errorkind,并且link属性必须指定链式错误的路径。

    当启用proc_macro功能时,link属性的值不需要进行字符串化。

    #
    #
    #
    #[error_chain(link = other_error::Error)]
    Another(other_error::ErrorKind),
    
  • 外部链接

    #
    #[error_chain(foreign)]
    Fmt(::std::fmt::Error),
    

    外部链接是一种错误,它实现了 ::std::error::Error,但其他方面不遵循 error-chain 的约定。变体必须有一个字段来存储外部错误。

  • 自定义链接

    #
    #[error_chain(custom)]
    InvalidToolchainName(String),
    

    自定义链接是一个任意变体,可以持有任何成员。

变体属性

除了上述标识变体链接类型的属性外,以下属性可以用于所有链接。

  • #[error_chain(描述= "some_function_expression")]

    指定一个函数表达式,用于实现 ErrorKind::description()。此值也返回自生成的 Error::std::error::Error::description() 的实现。

    这可以是一个内联lambda

    #
        # #[error_chain(custom)]
    #[error_chain(description = r#"|_| "invalid toolchain name""#)]
    InvalidToolchainName(String),
    

    或者它可以是单独的函数

    #
        # #[error_chain(custom)]
    #[error_chain(description = "invalid_toolchain_name_error_description")]
    InvalidToolchainName(String),
    
    // <snip>
    
    fn invalid_toolchain_name_error_description(_: &str) -> &str {
        "invalid toolchain name"
    }
    

    函数表达式必须具有签名 (...) -> &'static str。它应该有一个参数对应于变体的每个字段。字段通过引用传递。

    因此,在上面的例子中,由于 InvalidToolchainName 只有一个类型为 String 的字段,函数表达式需要是类型 (&str) -> &'static str

    如果没有指定,默认实现的行为是这样的

    • 链式链接:转发到链式错误类型的 description()
    • 外部链接:转发到外部错误的 ::std::error::Error::description() 实现
    • 自定义链接:返回变体的字符串化名称。

    当启用 proc_macro 功能时,不需要将值字符串化

    #
    #
        # #[error_chain(custom)]
    #[error_chain(description = |_| "invalid toolchain name")]
    InvalidToolchainName(String),
    
    #
    #
        # #[error_chain(custom)]
    #[error_chain(description = invalid_toolchain_name_error_description)]
    InvalidToolchainName(String),
    #
    

    当启用 proc_macro 功能时,仅调用 write! 的闭包表达式可以替代简写

    #
    #
        # #[error_chain(custom)]
    #[error_chain(description = const("invalid toolchain name"))]
    InvalidToolchainName(String),
    
  • #[error_chain(显示= "some_function_expression")]

    指定一个函数表达式,用于在 ErrorKind 和生成的 Error 上实现 ::std::fmt::Display::fmt()

    这可以是一个内联lambda

    #
        # #[error_chain(custom)]
    #[error_chain(display = r#"|t| write!(f, "invalid toolchain name: '{}'", t)"#)]
    InvalidToolchainName(String),
    

    或者它可以是单独的函数

    #
        # #[error_chain(custom)]
    #[error_chain(display = "invalid_toolchain_name_error_display")]
    InvalidToolchainName(String),
    
    // <snip>
    
    fn invalid_toolchain_name_error_display(f: &mut ::std::fmt::Formatter, t: &str) -> ::std::fmt::Result {
        write!(f, "invalid toolchain name: '{}'", t)
    }
    

    函数表达式必须具有以下签名:(&mut ::std::fmt::Formatter, ...) -> ::std::fmt::Result。它应该有一个 &mut ::std::fmt::Formatter 参数,以及一个参数对应变体的每个字段。字段通过引用传递。为了简洁,闭包表达式不需要 &mut ::std::fmt::Formatter 参数,而是从闭包环境中捕获 f

    因此,在上面的例子中,由于 InvalidToolchainName 只有一个类型为 String 的字段,函数表达式必须具有类型 (&mut ::std::fmt::Formatter, &str) -> ::std::fmt::Result

    如果没有指定,默认的 ::std::fmt::Display::fmt() 实现将以这种方式行为

    • 链式链接:转发到链式 errorkind 的 ::std::fmt::Display::fmt() 实现中
    • 外部链接:转发到外部错误的 ::std::fmt::Display::fmt() 实现中
    • 自定义链接:将变体的描述写入格式化器。

    当启用 proc_macro 功能时,不需要将值字符串化

    #
    #
        # #[error_chain(custom)]
    #[error_chain(display = |t| write!(f, "invalid toolchain name: '{}'", t))]
    InvalidToolchainName(String),
    
    #
    #
        # #[error_chain(custom)]
    #[error_chain(display = invalid_toolchain_name_error_display)]
    InvalidToolchainName(String),
    #
    

    当启用 proc_macro 功能时,仅调用 write! 的闭包表达式可以替代简写

    #
    #
    // Tuple variants use `{0}`, `{1}`, and so on
        # #[error_chain(custom)]
    #[error_chain(display = const("invalid toolchain name: '{0}'"))]
    InvalidToolchainName(String),
    
    #
    #
    // Struct variants use `{name_of_the_field}`
        # #[error_chain(custom)]
    #[error_chain(display = const("invalid toolchain name: '{name}'"))]
    InvalidToolchainName { name: String },
    
  • #[error_chain(原因= "some_function_expression")]

    指定一个函数表达式,用于在生成的 Error 上实现 ::std::fmt::Error::cause()

    这可以是一个内联lambda

    #
        # #[error_chain(custom)]
    #[error_chain(cause = "|_, err| err")]
    Io(::std::path::PathBuf, ::std::io::Error),
    

    或者它可以是单独的函数

    #
        # #[error_chain(custom)]
    #[error_chain(cause = "parse_file_error_cause")]
    Io(::std::path::PathBuf, ::std::io::Error),
    
    // <snip>
    
    fn parse_file_error_cause<'a>(_: &::std::path::Path, err: &'a ::std::io::Error) -> &'a ::std::error::Error {
        err
    }
    

    函数表达式必须具有以下签名:(...) -> &::std::error::Error。它应该为变体的每个字段有一个参数。字段通过引用传递。结果是包装在 Option::Some() 中,以从 ::std::error::Error::cause()

    因此,在上面的例子中,由于 Io 有两个类型为 ::std::path::PathBuf::std::io::Error 的字段,函数表达式需要具有类型 (&::std::path::Path, &::std::io::Error) -> &::std::error::Error

    如果没有指定,::std::error::Error::cause() 的默认实现将按这种方式行为

    • 链式链接:返回 None
    • 外部链接:转发到外部错误的 ::std::error::Error::cause() 实现中
    • 自定义链接:返回 None

    当启用 proc_macro 功能时,不需要将值字符串化

    #
    #
        # #[error_chain(custom)]
    #[error_chain(cause = |_, err| err)]
    Io(::std::path::PathBuf, ::std::io::Error),
    
    #
    #
        # #[error_chain(custom)]
    #[error_chain(cause = parse_file_error_cause)]
    Io(::std::path::PathBuf, ::std::io::Error),
    #
    

当启用 proc_macro 功能时,与 error-chain 宏冲突

如果您启用了 proc_macro 功能并且有如下代码:

#![feature(proc_macro)]

#[macro_use] extern crate derive_error_chain;
#[macro_use] extern crate error_chain; // Want to use `bail!` and `quick_main!`

#[derive(Debug, ErrorChain)]
#[error_chain(result = "MyResult")]
enum ErrorKind {
    Msg(String),
}

quick_main!(|| -> MyResult<()> {
    bail!("failed");
});

它将无法编译

error: macro `error_chain` may not be used in attributes

这是因为在编译器看来,#[error_chain(result = "MyResult")] 是一个属性宏的调用,它注意到 error_chain! 是从 error-chain 包中引入的 macro_rules 宏,因此抱怨 macro_rules 宏不能用作属性宏。即使没有名为 error_chain 的属性宏,并且从这个包中自定义 derive 已将 error_chain 注册为支持的属性,它也会这样做。

有关讨论,请参阅 https://github.com/rust-lang/rust/issues/38356#issuecomment-324277403

为了解决这个问题,不要在 error-chain 包中使用 #[macro_use]。相反,要么从其中 use 你需要的宏

#![feature(proc_macro)]

#[macro_use] extern crate derive_error_chain;
extern crate error_chain;

use error_chain::{ bail, quick_main };

#[derive(Debug, ErrorChain)]
#[error_chain(result = "MyResult")]
enum ErrorKind {
    Msg(String),
}

quick_main!(|| -> MyResult<()> {
    bail!("failed");
});

或者完全限定它们的路径

#![feature(proc_macro)]

#[macro_use] extern crate derive_error_chain;
extern crate error_chain;

#[derive(Debug, ErrorChain)]
#[error_chain(result = "MyResult")]
enum ErrorKind {
    Msg(String),
}

error_chain::quick_main!(|| -> MyResult<()> {
    error_chain::bail!("failed");
});

使用 error_chain! 宏本身更为复杂:它必须重命名,以防止再次产生上述错误,并且它使用的其他宏也必须导入,尽管它们是实现细节

#![feature(proc_macro)]

#[macro_use] extern crate derive_error_chain;
extern crate error_chain;

use error_chain::{ error_chain as error_chain_macro, error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, impl_extract_backtrace };

#[derive(Debug, ErrorChain)]
#[error_chain(error = "MyError", result = "MyResult", result_ext = "MyResultExt")]
enum MyErrorKind {
    Msg(String),
}

error_chain_macro! {
}

为了完全限定使用,它所依赖的宏仍然需要 use 来将其引入作用域

#![feature(proc_macro)]

#[macro_use] extern crate derive_error_chain;
extern crate error_chain;

use error_chain::{ error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, impl_extract_backtrace };

#[derive(Debug, ErrorChain)]
#[error_chain(error = "MyError", result = "MyResult", result_ext = "MyResultExt")]
enum MyErrorKind {
    Msg(String),
}

error_chain::error_chain! {
}

proc_macro 功能稳定之前,这个体验可能会变得更好。

依赖关系

~2MB
~47K SLoC