2016 年的 Rust

2015 年 8 月 14 日 · Nicholas Matsakis 和 Aaron Turon

本周是 Rust 1.0 发布三个月。当我们开始进入 1.0 后的发展阶段时,我们想谈谈 **从后见之明来看,1.0 的意义,以及我们认为 Rust 在未来一年的发展方向**。

关于 1.0 的意义

Rust 1.0 的重点是稳定性、社区和清晰性。

总而言之,**Rust 之所以令人兴奋,是因为它赋予了力量:你可以无所畏惧地进行编码**。并且你可以在以前可能没有过的环境中这样做,从 Ruby 或 Python 等语言下降,首次尝试系统编程。

这就是 Rust 1.0;但接下来会发生什么?

我们从这里走向何方

在核心团队、早期生产用户和更广泛的社区进行了大量讨论之后,我们确定了未来一年左右要进行的一些改进,这些改进分为三个类别:

  • 加倍投入基础设施;
  • 缩小关键功能中的差距;
  • 扩展到使用 Rust 的新领域。

让我们来看看每个类别中一些最大的计划。

加倍投入:基础设施投资

Crater

Rust 的基本稳定性承诺是版本之间的升级是“无忧无虑”的。为了实现这一承诺,我们需要检测导致代码停止工作的编译器错误。当然,编译器有自己的大型测试套件,但这只是“在野外”存在的代码的一小部分。**Crater 是一种工具,旨在通过针对 crates.io 中找到的所有软件包测试编译器来弥合这一差距,从而让我们更好地了解是否有任何代码在最新的 nightly 版本中停止编译。**

Crater 很快成为不可或缺的工具。我们会定期将 nightly 版本与最新的稳定版本进行比较,并使用 crater 来检查正在进行的的分支并评估更改的影响。

有趣的是,我们经常发现,当代码停止编译时,并不是因为编译器中存在错误。相反,是因为我们*修复*了一个错误,而该代码恰好依赖于较旧的行为。即使在这些情况下,使用 crater 也可以通过建议我们应该通过警告逐步修复来帮助我们改善体验。

在未来一年左右的时间里,我们计划在多个方面改进 crater:

  • 将覆盖范围扩展到 Linux 以外的其他平台,并在覆盖的库上运行测试套件。
  • 使其更易于使用:留下 @crater: test 注释以试用 PR。
  • 生成一个工具版本,库作者可以使用该工具来查看其更改对下游代码的影响。
  • 包括来自 crates.io 以外的其他来源的代码。

增量编译

Rust 一直采用“crate 范围”的编译模型。这意味着 Rust 编译器会一次读取 crate 中的所有源文件。这些文件会进行类型检查,然后传递给 LLVM 进行优化。这种方法非常适合进行深度优化,因为它使 LLVM 可以完全访问整个代码集,从而可以进行更好的内联、更精确的分析等等。但是,这可能意味着周转速度很慢:即使你只编辑一个函数,我们也会重新编译所有内容。当项目变得很大时,这可能会成为负担。

增量编译项目的目标是通过让 Rust 编译器保存中间产物并重新使用它们来改变这种情况。这样,当你调试问题或调整代码路径时,**你只需重新编译你已更改的内容,这应该会使“编辑-编译-测试”周期快得多**。

该项目的一部分是重组编译器以引入新的中间表示,我们称之为 MIR。MIR 是一种更简单、更低级别的 Rust 代码形式,它简化了更复杂的功能,使编译器的其余部分更简单。这是非词法生命周期(在下一节中讨论)等语言更改的关键推动因素。

IDE 集成

一流的 IDE 支持可以帮助提高 Rust 的生产力。到目前为止,RacerVisual RustRust DT 等开创性项目主要是在没有编译器支持的情况下工作的。**我们计划扩展编译器,以允许与 IDE 和其他工具进行更深入的集成**;该计划最初将重点放在两个 IDE 上,然后再从那里发展。

聚焦:缩小关键功能中的差距

特化

零成本抽象的思想分解为两个独立的目标,正如 Stroustrup 所确定的那样:

  • 你不使用的东西,你就不必为此付出代价。
  • 你使用的东西,你不可能用手编码得更好。

Rust 1.0 在语言功能和标准库方面基本上实现了第一个目标。但它并没有完全实现第二个目标。以以下 trait 为例:

pub trait Extend<A> {
    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=A>;
}

Extend trait 提供了一种很好的抽象,用于将来自任何类型的迭代器的数据插入到集合中。但是,在今天的 trait 中,这也意味着每个集合只能提供一个适用于*所有*迭代器类型的实现,这需要实际重复调用 .next()。在某些情况下,你可以用手编码得更好,例如,只需调用 memcpy

为了弥合这一差距,我们提出了 **特化,允许你提供多个重叠的 trait 实现,只要其中一个明显比另一个更具体即可**。除了为 Rust 提供更完整的零成本抽象工具包外,特化还改善了其代码重用的故事。有关更多详细信息,请参阅 RFC

借用检查器改进

借用检查器在某种程度上是 Rust 的跳动心脏;它是编译器的一部分,通过捕获 use-after-free 错误等,使我们能够在没有垃圾回收的情况下实现内存安全。但有时,借用检查器也会“捕获”非错误,如下面的模式所示:

match map.find(&key) {
    Some(...) => { ... }
    None => {
        map.insert(key, new_value);
    }
}

像上面的代码片段这样的代码是完全没问题的,但借用检查器今天很难处理它,因为 map 变量在整个 match 主体中都被借用了,从而阻止它被 insert 修改。我们计划通过重构借用检查器来解决这个缺点,使其以更精细的(“非词法”)区域来查看代码——这是通过转移到上面提到的 MIR 来实现的。

插件

如果你愿意使用 Nightly 频道,今天你可以在 Rust 中做一些非常巧妙的事情。例如,regex crate 带有宏,可以在编译时将正则表达式直接转换为匹配它们的机器代码。或者以 rust-postgres-macros crate 为例,它会在编译时检查字符串的 SQL 语法有效性。像这样的 crate 利用了一个高度不稳定的编译器插件系统,该系统目前暴露了太多的编译器内部结构。**我们计划提出一种新的插件设计,该设计更健壮,并提供对卫生宏扩展的内置支持**。

扩展:将 Rust 带到新的领域

交叉编译

虽然今天可以使用 Rust 进行交叉编译,但它涉及大量的手动配置。**我们正在努力实现一键式交叉编译**。我们的想法是,为另一个目标编译 Rust 代码应该很容易:

  1. 如果你还没有为目标下载预编译版本的 libstd
  2. 执行 cargo build --target=foo
  3. 没有第 3 步。

Cargo 安装

Cargo 和 crates.io 是一个非常好的库分发工具,但它缺少任何安装可执行文件的方法。RFC 1200 描述了对 cargo 的一个简单添加,即 cargo install 命令。与传统的 make install 非常相似,**cargo install 会将可执行文件放置在你的路径中,以便你可以运行它**。这可以作为一个简单的分发渠道,对于编写以 Rust 开发人员为目标的工具的人特别有用(他们可能熟悉运行 cargo)。

跟踪钩子

使用 Rust 最有前景的方式之一是将 Rust 代码“嵌入”到使用更高级语言编写的系统中,例如 Ruby 或 Python。这种嵌入通常通过为 Rust 代码提供 C API 来实现,当目标采用“C 友好”的内存管理方案(如引用计数或保守 GC)时,效果相当不错。

与使用更高级 GC 的环境集成可能会非常具有挑战性。最突出的例子或许是 JavaScript 引擎,例如 V8(由 node.js 使用)和 SpiderMonkey(由 FirefoxServo 使用)。与这些引擎集成需要非常谨慎的编码,以确保所有对象都正确地被根引用;小的错误很容易导致崩溃。而这些正是 Rust 旨在消除的内存管理问题。

为了将 Rust 带入具有高级 GC 的环境,我们计划扩展编译器,使其能够生成“跟踪钩子”。GC 可以使用这些钩子来扫描堆栈并识别根,从而可以编写能够与高级 VM 平滑且轻松集成的代码。当然,该设计将尊重 Rust 的“按需付费”原则,因此不与 GC 集成的代码不会受到影响。

尾声:RustCamp 2015 和 2016 年的 Rust 社区

我们最近举办了有史以来第一次 Rust 会议,RustCamp 2015,有 160 名与会者,门票全部售罄。看到如此多的 Rust 社区成员亲临现场,并看到我们在线空间的氛围转化为友好且平易近人的线下活动,真是令人惊叹。第一天以 Nicholas Matsakis 和 Aaron Turon 的主题演讲开幕,他们阐述了核心团队对我们所处位置以及未来发展方向的看法。幻灯片已在网上提供(以及其他几个演讲),以上内容可以作为缺失的背景音乐。 更新:现在您还可以观看演讲视频

当天有一个明确的主题:Rust 最大的潜力是开启新一代系统程序员。这不仅仅是因为语言本身;还因为社区文化提倡“不知道堆栈和堆的区别?不用担心,Rust 是了解它的好方法,我很乐意向你展示如何学习。”

我们上面概述的技术工作对于我们在 2016 年的愿景至关重要,我们社区管理和社区团队的工作,以及所有那些不知疲倦地(热情地)欢迎来自各种背景的人们加入 Rust 社区的人们的工作,也同样重要。因此,我们对 Rust 未来一年的最大愿望是,随着社区的发展,它能够继续保持今天所拥有的欢迎精神。