Rust 世界正在发生变化。如果你尝试过最新的 nightly 版本,你会注意到有些东西有点不同。在过去的几个月里,我们一直在努力开发一种新的错误报告方式,这种方式更容易阅读和理解。这是我们持续改进 Rust 可用性的一个环节。我们提到了帮助我们过渡到新的错误的方法,并且已经有很多朋友加入了(感谢这些志愿者!)。
让我们深入了解一下发生了哪些变化。我们从一个简单的例子开始。
fn borrow_same_field_twice_mut_mut() {
let mut foo = make_foo();
let bar1 = &mut foo.bar1;
let _bar2 = &mut foo.bar1;
*bar1;
}
在这里,我们犯了一个错误,即对同一个值进行两次可变借用。这是 Rust 中一个经典的错误。当然,之前的编译器给我们的错误信息基本上就是这个意思。
但问题是,需要花几秒钟才能查看消息,定位自己,并找到关键部分。这种时间损失会累积起来。如果我们能清除所有减慢你阅读错误消息速度的东西,会怎么样呢?
这就是新的错误格式。它的设计基于一个基本观察结果,即错误应该重点关注你编写的代码。通过这样做,你可以更容易地看到正在发生的事情的上下文。
设计
关键的见解是将你的源代码放在最前面 - 你在输出中看到的所有内容都是基于你的代码的。通过使用你编写的代码作为上下文,我们为你提供了一种简单的方法,让你一眼就能知道问题发生在哪里。
常量评估错误
接下来,一旦我们知道了位置,我们就需要解释哪里出了问题。我们通过标记代码中帮助解释错误的兴趣点来做到这一点。最明显的地方是错误发生的地方。这是错误的“什么”。
在这个例子中,你可以看到我们如何使用这些主要标签。有了它们,你的眼睛就能看到有问题的代码,以及关于问题的一些文字。由于这是最需要先看到的地方,所以我们用一个醒目的红色外观和一个特征性的^^^
下划线来标记它们。你会注意到,在这个例子中,这种组合让你可以快速地发现错误并理解哪里出了问题。
与特征要求不匹配的错误
错误的来源并不是唯一的兴趣点。通常还有其他兴趣点可以帮助描述错误发生的“原因”。通过阅读这些次要标签,你可以更好地理解哪里出了问题。这些标签按照它们在你的代码中出现的顺序显示,同样是为了确保你始终能够一眼就明白自己身处何处。
在这个例子中,次要标签显示了特征的原始要求,这样你就可以同时看到它,并自己比较要求和实现。
主要标签和次要标签共同讲述了一个关于哪里出了问题的事件。由于 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 体验中任何令人困惑或分散注意力的部分,并对其进行适当的改进。错误是我们应用这种改进的一个领域,它有助于我们一点一点地改善学习曲线,我们期待着看到我们能走多远。