如何在Rust中定义自定义`Error`类型?

Jo Liss:

我正在编写一个函数,该函数可能返回几种不同错误中的几种。

fn foo(...) -> Result<..., MyError> {}

我可能需要定义自己的错误类型来表示此类错误。我认为这可能是一个enum错误,其中某些enum变体附带了诊断数据:

enum MyError {
    GizmoError,
    WidgetNotFoundError(widget_name: String)
}

这是最惯用的方式吗?以及如何实现该Error特征?

Shepmaster:

你实施的方式Error其他任何特质一样 ; 没有什么特别的:

pub trait Error: Debug + Display {
    fn description(&self) -> &str { /* ... */ }
    fn cause(&self) -> Option<&Error> { /* ... */ }
    fn source(&self) -> Option<&(Error + 'static)> { /* ... */ }
}

description,,causesource都具有默认实现1,并且您的类型也必须实现DebugDisplay,因为它们是上位性。

use std::{error::Error, fmt};

#[derive(Debug)]
struct Thing;

impl Error for Thing {}

impl fmt::Display for Thing {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Oh no, something bad went down")
    }
}

当然,Thing其中包含的内容以及方法的实现在很大程度上取决于您希望出现的错误类型。也许您想在其中包含文件名,或者某种某种整数。也许您想用enum而不是a struct来代表多种类型的错误。

如果您最终包装了现有错误,那么我建议您实施From以在这些错误和您的错误之间进行转换。这使您可以使用try!?拥有一个符合人体工程学的漂亮解决方案。

这是最惯用的方式吗?

习惯上讲,我想说一个库将暴露少量(也许是1-3)主要错误类型。这些可能是其他错误类型的枚举。这样一来,您的板条箱使用者就不必处理大量的类型。当然,这取决于您的API,以及是否将一些错误集中在一起是否有意义。

要注意的另一件事是,当您选择将数据嵌入错误中时,可能会产生广泛的后果。例如,标准库在与文件相关的错误中不包含文件名。这样做会增加每个文件错误的开销。该方法的调用者通常具有相关的上下文,并且可以决定是否需要将该上下文添加到错误中。


我建议您手动进行几次,以查看所有部件如何组合在一起。一旦有了这些,您就会对手动完成工作感到厌倦。然后,您可以检出提供宏以减少样板的板条箱:

我首选的库是SNAFU(因为我写了它),因此这是将其与原始错误类型结合使用的示例:

// This example uses the simpler syntax supported in Rust 1.34
use snafu::Snafu; // 0.2.0

#[derive(Debug, Snafu)]
enum MyError {
    #[snafu(display("Refrob the Gizmo"))]
    Gizmo,
    #[snafu(display("The widget '{}' could not be found", widget_name))]
    WidgetNotFound { widget_name: String }
}

fn foo() -> Result<(), MyError> {
    WidgetNotFound { widget_name: "Quux" }.fail()
}

fn main() {
    if let Err(e) = foo() {
        println!("{}", e);
        // The widget 'Quux' could not be found
    }
}

注意我已经删除了Error每个枚举值的冗余后缀。仅调用类型Error并允许使用者为类型加上前缀(mycrate::Error)或在导入(use mycrate::Error as FooError上重命名也是很常见的


1实施RFC 2504之前,这description是必需的方法。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在Rust中过滤自定义结构的向量?

如何在Go中创建自定义类型元素的自定义类型数组?

如何在Go中遍历自定义类型的数组?

如何在TypeScript中迭代自定义文字类型?

如何在Java中创建自定义异常类型?

如何在Azure中自定义用户属性的类型?

如何在自定义类型中测试确保的值?

如何在Delphi中声明自定义类型?

如何在 sqlalchemy 中“检查”自定义类型

如何在Android中添加自定义mime类型?

如何在Typescript中定义自定义类型以防止“无法分配给类型...”

如何在Swift中合并两个自定义类型数组并删除重复的自定义类型项?

如何在 umbraco 中创建表示自定义数据类型列表的自定义数据类型?

如何在WordPress响应中显示自定义帖子类型的JSON响应中的自定义字段?

如何在F#中为自定义类型定义一元减号?

如何在一行中声明和定义自定义类型的变量

如何在Perl 6中定义Ints的Arrayreference的自定义类型?

如何在Spark SQL中为自定义类型定义架构?

如何读取与 Rust 中的自定义类型关联的枚举值?

如何在Swift中的自定义类型和现有类型之间允许类型转换

如何在 Wordpress 中为自定义帖子类型加载自定义样式表?

如何在WordPress中自定义帖子类型的自定义类别的帖子循环?

如何在页面或自定义帖子类型中复制一组自定义字段?

如何添加自定义类型定义?

如何在Rust中的自定义单线程迭代器上并行化map(...)

如何在Rails中定义自定义配置变量

如何在Dymola中定义记录的自定义参数?

如何在ckeditor中定义自定义html标签

如何在 Maple 中定义自定义函数?