Rust 世界正在发生变化。如果你试用了最新的 nightly 版本,你会注意到有些东西是有点不一样的。在过去的几个月里,我们一直在致力于改进错误报告方式,使其更容易阅读和理解。这是提高 Rust 整体可用性持续工作的一部分。我们提到了帮助我们完成向新错误过渡的方法,而且许多人已经加入了进来(在此感谢那些志愿者!)
让我们深入了解并看看有什么变化。我们从一个简单的例子开始
这里我们犯了一个错误,对同一个值进行了两次可变借用。这是 Rust 中的一个经典错误。果然,之前的编译器给出的错误信息大致如此
然而问题在于,你需要花几秒钟查看信息、理清思路并找到关键部分。这种时间损耗累积起来。如果我们去掉所有会减慢你阅读错误信息速度的东西,会怎么样?

这是新的错误格式。它的设计围绕一个基本观察:错误应该聚焦于你编写的代码。这样做,你可以更容易地看到正在发生的事情的上下文。
设计
关键的洞察在于将你的源代码放在显眼位置——你在输出中看到的一切都基于你的代码。通过使用你编写的代码作为上下文,我们为你提供了一种一目了然地知道问题发生位置的简便方法。
常量求值错误
接下来,一旦我们知道了位置,就需要解释哪里出了问题。我们通过在代码中标记有助于解释错误的兴趣点来做到这一点。最明显的标记位置是错误发生的地方。这是错误的“是什么”。
在这个例子中,你可以看到我们如何使用这些主标签。有了它们,你的目光既可以看到有问题的代码,也可以看到关于问题的一些文字。由于这是第一个最重要的查看位置,我们给它们醒目的红色外观,并带有标志性的 ^^^
下划线。你会注意到,在这个例子中,这种组合让你能够快速发现错误并理解哪里出了问题。
与 trait 要求不匹配的错误
错误的来源并非唯一的兴趣点。通常还有其他兴趣点有助于描述错误“为什么”会发生。通过阅读这些次要标签,你可以更好地理解哪里出了问题。这些标签按照它们在你的代码中出现的顺序显示,同样是为了确保你始终能够一目了然地知道你身在何处。
在这个例子中,次要标签显示了 trait 的原始要求,这样你可以同时看到它,并自行比较要求和实现。
主标签和次要标签协同工作,讲述了哪里出了问题的故事。由于 Rust 非常关注借用检查器和内存安全,用户在遇到这些错误时可能会看到不熟悉的概念。这些标签有助于引导他们理解即使是像借用错误这样不熟悉的错误是如何发生的。
名称不在作用域内,附带建议
有时信息太多,无法全部放在标签上,因此新格式也支持附加额外注释。就像之前的错误格式一样,新格式支持警告、建议、提示等。
扩展错误消息
更新错误消息格式后,我们寻找了可以应用所学经验的其他领域。显而易见的首选是 --explain
消息。顾名思义,--explain
功能允许开发者通过更长、更详细的解释来探索不熟悉的错误消息。
今天,当你调用 --explain
时,你会传递一个错误代码。编译器随后会打印出一条扩展消息,更详细地解释该形式的错误是如何发生的
$ rustc --explain E0200
Unsafe traits must have unsafe implementations. This error occurs when an
implementation for an unsafe trait isn't marked as unsafe. This may be resolved
by marking the unsafe implementation as unsafe.
struct Foo;
unsafe trait Bar { }
// this won't compile because Bar is unsafe and impl isn't unsafe
impl Bar for Foo { }
// this will compile
unsafe impl Bar for Foo { }
这是帮助弥合错误和学习 Rust 中不熟悉概念之间差距的好方法。
虽然此消息很有帮助,但它使用了可能与你的代码无关的通用示例。借鉴错误消息的工作经验,我们将更新解释消息,使其专注于你的代码。例如,对于我们开始时遇到的借用检查器错误,我们可能会有一个看起来像这样的扩展错误消息
error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
--> src/test/compile-fail/borrowck/borrowck-borrow-from-owned-ptr.rs:29:22
The borrow checker detected that `foo.bar1` was borrowed multiple
times as a mutable value. In Rust, this can not be done safely because
there may be multiple owners of the value who may write to it at the
same time. If this happens in parallel, the resulting value may be in
an unknown state.
Because this is unsafe, Rust disallows having multiple owners of the
same mutable value.
This is the first time `foo.bar1` is borrowed mutably.
28 | let bar1 = &mut foo.bar1;
| --------
And this is the second time `foo.bar1` is borrowed mutably. This is
where the error occurs.
29 | let _bar2 = &mut foo.bar1;
| ^^^^^^^^
Note that the first borrow of `foo.bar1` continues until the borrow
is released. During this time, no additional borrows can occur. This
first borrow ends here:
31 | }
| -
After the first borrow has ended you are able to borrow it again. To
fix this issue, if you need to borrow a value as mutable more than
once, ensure that the span of time they are borrowed do not overlap.
在上面,你看到了这种新的模板化风格的可能输出。熟悉 Elm 风格的人可能会意识到,更新后的 --explain
消息借鉴了 Elm 方法的许多灵感。
目前,这种格式仍在设计和开发中。如果你想帮助我们塑造扩展错误的外观,请加入 irc.mozilla.org 上的 #rust-cli 频道。
我想帮忙!
太好了!我们很喜欢这种热情。有很多工作要做,以及许多不同领域的技能可以帮助我们。无论你擅长单元测试、编写文档、编写代码还是进行设计,都有可以加入的地方。
结论
改进 Rust 是一项持续进行的活动。鉴于解决 Rust 学习曲线问题是Rust 调查中的一个关键主题,我们一如既往地有动力去找出 Rust 体验中任何令人困惑或分心的地方,并进行大量的润色。错误是我们正在应用润色的一个领域,这有助于我们一点一点地改善学习曲线,我们期待看到我们能走多远。