Rust 社区非常重视错误处理。在强调有用的错误处理和报告方面,已经形成了强大的文化,有多个库各自提供了自己的方法(请参阅 Jane Lusby 对 Rust 错误处理/报告库的详尽 调查)。
但仍有改进空间。该小组的主要重点是继续进行在小组成立之前正在进行的与错误处理相关的工作。为此,我们正在系统地解决与错误处理相关的问题,并消除阻碍已停滞 RFC 的障碍。
在我们最初的几次会议中,我们设定了一些短期和长期目标。这些目标分为三个主题:使 Error
trait 更普遍地访问,提高错误处理的效率,以及编写额外的学习资源。
Error
Trait
一个标准化的 Error
trait 自 1.0 版本以来就存在,并暴露了两个方法:Error::description
和 Error::cause
。由于最初的构造方式,它在许多方面都过于严格1。Failure
crate 通过导出 Fail
trait 解决了 Error
trait 的许多缺点,这为改进 Error
trait 的许多更改提供了依据。
在此基础上,自 RFC 2504 于 2018 年 8 月合并以来,增强 std::error::Error
trait,使其可以在 Rust 社区中作为 *the* Error
trait 被采用,这是一个持续的过程。
这个过程还涉及稳定许多 Error
trait API 和 crate,截至撰写本文时,它们仅在 nightly 版本中可用。其中包括 backtrace
和 chain
方法,它们对于处理错误类型都非常有用。如果您有兴趣关注或为此工作做出贡献,请查看 此 issue。
另一个相关的举措是将 Error
trait 迁移到 core
,以便它更广泛地适用于不同的用例(例如 FFI 或嵌入式环境)。
更多访问错误上下文的方式
Rust 的语言语义已经提供了相当符合人体工程学的错误处理体验,包括 Result
类型和 ?
运算符。错误处理小组已经确定了一些其他功能,以进一步改善错误处理的用户体验。
Backtrace
类型的功能
添加遍历 截至撰写本文时,backtrace
类型仅实现了 Display
和 Debug
trait。这意味着处理 backtrace
类型的唯一方法是将其打印出来,这不太理想。提供遍历堆栈帧能力的迭代器 API 将使用户能够控制其回溯的格式,这是为 color-backtrace
等 crate 添加 std::backtrace::Backtrace
支持的必要步骤。
在研究如何解决此问题的策略时,我们发现 backtrace
crate 已经有一个 frames
方法,可以很好地用于实现 Iterator
API。在 std
中公开相同的方法应该是一个相对简单的过程。
为此,已经打开了一个 PR,供任何想查看的人查看。
泛型成员访问
目前,当我们想获取一些与错误相关的额外上下文时,需要调用特定的方法才能获取该上下文。例如,要查看错误的堆栈跟踪,我们需要调用 backtrace
方法:let backtrace = some_error.backtrace();
。这种方法的问题在于,它不可能支持在 std
之外定义的类型。即使对于 std
中存在的类型,也需要定义一个访问每个各自类型的方法,这使得事情变得繁琐且难以维护。
顾名思义,泛型成员访问在实现后,将是一种类型无关的方式,可以从 Error
trait 对象访问不同的上下文片段。让我印象深刻的一个类比是,当您将字符串解析为数字时,使用如下方法:
let ten = "10".parse::<i32>();
或者当您收集迭代器产生的内容时:
use std::collections::HashSet;
let a_to_z_set = ('a'..='z').collect::<HashSet<_>>();
类似地,您可以通过指定其类型 ID 来访问错误的某些上下文片段:
let span_trace = some_error.context::<&SpanTrace>();
这可以用来获取与错误相关的其他上下文片段,例如其回溯、错误的来源、状态代码、其他格式表示形式(例如 &dyn Serialize
)。
此功能将启用我们计划稍后添加的其他功能,例如公开一种报告程序中错误来源的所有位置的方式,以及公开除 Display
和 Debug
之外更一致的错误报告格式。
Jane 一直在为推进这些想法做了很多工作。您可以查看相关的 RFC。
编写一本关于 Rust 错误处理最佳实践的书籍
最后但并非最不重要的一点是,该小组对编写 《Rust 错误书籍》 有很大的兴趣。这本书的目的是根据各自的用例来整理和传达不同的错误处理最佳实践。这可能包括 FFI 用例,或有关从程序返回错误代码的最佳实践。
这是一项正在进行的工作,将在未来几周和几个月内取得很大进展!
总结
我们对继续迭代和改进 Rust 的错误处理效率和文化的机会感到兴奋!如果您有兴趣提供帮助和/或加入讨论,请来我们的 Zulip 流 自我介绍。您还可以通过我们的 GitHub 存储库 跟踪我们的进度。
最后,我们将在下一次更新中发布有关普遍一致的错误报告格式的最新消息,敬请关注!
脚注
1Error::description
方法仅支持字符串切片,这意味着创建包含额外上下文的动态错误消息并不简单。此方法已弃用,转而使用 Display
。Error::cause
方法,现在称为 Error::source
,不强制错误具有 'static
生命周期,这意味着不可能向下转换错误源,这使得使用动态错误处理程序处理错误更加困难。