Rust 五周年

2020 年 5 月 15 日 · Rust 核心团队

鉴于世界上发生的一切,你可能会忘记,今天是 Rust 1.0 发布五周年!Rust 在过去五年中发生了很大变化,因此我们想回顾一下自语言稳定化以来所有贡献者的工作。

Rust 是一种通用编程语言,它使每个人都能构建可靠且高效的软件。Rust 可以构建为在堆栈中的任何位置运行,无论是作为操作系统的内核还是下一个 Web 应用程序。它完全由一个开放且多元的个人社区构建,主要是志愿者,他们慷慨地贡献自己的时间和专业知识,帮助 Rust 成为它现在的样子。

自 1.0 以来主要变化

2015

1.2 — 并行代码生成:编译时间改进是 Rust 每个版本的主题,很难想象 Rust 短时间内没有并行代码生成。

1.3 — Rustonomicon:我们发布了第一版很棒的“Rustonomicon”,这本书探讨了不安全的 Rust 及其相关主题,并已成为任何想要学习和理解语言中最难方面的人的宝贵资源。

1.4 — Windows MSVC 一级支持:第一个一级平台升级是为使用 Microsoft Visual C++ 工具链 (MSVC) 的 64 位 Windows 提供原生支持。在 1.4 之前,你需要安装 MinGW(第三方 GNU 环境)才能使用和编译 Rust 程序。Rust 的 Windows 支持是过去五年中最大的改进之一。最近,微软宣布了其对 WinRT API 的官方 Rust 支持的公开预览版!现在比以往任何时候都更容易构建高质量的原生和跨平台应用程序。

1.5 — Cargo 安装:能够在 cargo 的现有插件支持之外构建 Rust 二进制文件,催生了整个应用程序、实用程序和开发人员工具生态系统,社区已经开始喜欢和依赖这些工具。今天 cargo 的许多命令最初都是社区构建并在 crates.io 上共享的插件!

2016

1.6 — Libcore:libcore 是标准库的一个子集,它只包含不需要分配或操作系统级功能的 API。libcore 的稳定化带来了在没有分配或操作系统依赖的情况下编译 Rust 的能力,这是 Rust 支持嵌入式系统开发的第一步。

1.10 — C ABI 动态库:cdylib 箱类型允许 Rust 编译为 C 动态库,使你能够将 Rust 项目嵌入支持 C ABI 的任何系统中。Rust 在用户中取得的最大成功故事之一是能够用 Rust 编写系统中一小部分关键部分,并无缝地集成到更大的代码库中,现在比以往任何时候都更容易。

1.12 — Cargo 工作区:工作区允许你组织多个 Rust 项目并共享相同的锁文件。工作区在构建大型多箱级项目中非常宝贵。

1.13 — Try 运算符:第一个主要的语法添加是? 或“Try”运算符。该运算符允许你轻松地将错误传播到你的调用堆栈。以前你必须使用try! 宏,这要求你在每次遇到结果时都包装整个表达式,现在你可以轻松地使用? 而不是try! 来链接方法。

try!(try!(expression).method()); // Old
expression?.method()?;           // New

1.14 — Rustup 1.0:Rustup 是 Rust 的工具链管理器,它允许你无缝地使用任何版本的 Rust 或任何其工具。最初只是一个简单的 shell 脚本,现在已经成为维护者亲切地称为“奇美拉”的东西。能够在 Linux、macOS、Windows 和数十个目标平台上提供一流的编译器版本管理,五年前还是一个神话。

2017

1.15 — 派生过程宏:派生宏允许你创建功能强大且广泛的强类型 API,而无需所有样板代码。这是 Rust 的第一个版本,你可以在稳定版上使用serdediesel 的派生宏。

1.17 — Rustbuild:对语言贡献者来说,最大的改进之一是将我们的构建系统从最初的基于make 的系统迁移到使用 cargo。这使得rust-lang/rust 对于成员和新手来说更容易构建和贡献项目。

1.20 — 关联常量:以前常量只能与模块关联。在 1.20 中,我们稳定了将常量与结构体、枚举和最重要的特征关联。使在你的 API 中更容易为类型添加丰富的预设值集,例如常见的 IP 地址或有趣的数字。

2018

1.24 — 增量编译:在 1.24 之前,当你对库进行更改时,rustc 必须重新编译所有代码。现在 rustc 在缓存尽可能多的内容方面更加智能,只需要重新生成必要的内容。

1.26 — impl Trait:添加impl Trait 使你能够使用静态分派的优势和性能来获得表达式的动态 API。

1.28 — 全局分配器:以前你只能使用 rust 提供的分配器。使用全局分配器 API,你现在可以将分配器自定义为你需要的分配器。这是启用创建alloc 库的重要一步,alloc 库是标准库的另一个子集,它只包含需要分配器的 std 部分,例如VecString。现在比以往任何时候都更容易在各种系统上使用更多标准库部分。

1.31 — 2018 版:2018 版的发布是我们自 1.0 以来最大的版本,添加了一系列语法更改和改进,以完全向后兼容的方式编写 Rust,允许使用不同版本构建的库无缝地协同工作。

  • 非词法生命周期 对 Rust 的借用检查器进行了重大改进,使其能够接受更多可验证的安全代码。
  • 模块系统改进 对我们如何定义和使用模块进行了重大 UX 改进。
  • 常量函数 常量函数允许你在编译时运行和评估 Rust 代码。
  • Rustfmt 1.0 专为 Rust 构建的新代码格式化工具。
  • Clippy 1.0 Rust 的 linter,用于捕获常见错误。Clippy 使确保你的代码不仅安全而且正确变得更加容易。
  • Rustfix 随着所有语法更改,我们知道我们想要提供工具来使过渡尽可能容易。现在,当需要对 Rust 的语法进行更改时,只需一个cargo fix 就可以解决。

2019

1.34 — 备用箱注册表:随着 Rust 在生产中越来越多的使用,越来越需要能够在非公开空间中托管和使用你的项目,虽然 cargo 一直允许远程 git 依赖项,但使用备用注册表,你的组织可以轻松地构建和共享你自己的箱注册表,这些注册表可以在你的项目中使用,就像它们在 crates.io 上一样。

1.39 — Async/Await:用于处理 Future 的 async/await 关键字的稳定化是使 Rust 中的异步编程成为一等公民的主要里程碑之一。即使在发布后的短短六个月内,Rust 中的异步编程也已发展成为一个多样化且高效的生态系统。

2020

1.42 — 子切片模式:虽然不是最大的变化,但添加..(剩余)模式一直是期待已久的质量改进功能,它极大地提高了使用切片进行模式匹配的表达能力。

错误诊断

我们没有过多提及的一件事是 Rust 的错误消息和诊断自 1.0 以来有了多少改进。现在看看旧的错误消息,感觉就像在看另一种语言。

我们重点介绍了几个最佳展示我们改进程度的示例,这些示例向用户展示了他们在哪里犯了错误,重要的是帮助他们理解为什么它不起作用,并教他们如何修复它。

第一个示例(特征)
use std::io::Write;

fn trait_obj(w: &Write) {
    generic(w);
}

fn generic<W: Write>(_w: &W) {}
1.2.0 错误消息
   Compiling error-messages v0.1.0 (file:///Users/usr/src/rust/error-messages)
src/lib.rs:6:5: 6:12 error: the trait `core::marker::Sized` is not implemented for the type `std::io::Write` [E0277]
src/lib.rs:6     generic(w);
                 ^~~~~~~
src/lib.rs:6:5: 6:12 note: `std::io::Write` does not have a constant size known at compile-time
src/lib.rs:6     generic(w);
                 ^~~~~~~
error: aborting due to previous error
Could not compile `error-messages`.

To learn more, run the command again with --verbose.

A terminal screenshot of the 1.2.0 error message.

1.43.0 错误消息
   Compiling error-messages v0.1.0 (/Users/ep/src/rust/error-messages)
error[E0277]: the size for values of type `dyn std::io::Write` cannot be known at compilation time
 --> src/lib.rs:6:13
  |
6 |     generic(w);
  |             ^ doesn't have a size known at compile-time
...
9 | fn generic<W: Write>(_w: &W) {}
  |    ------- -       - help: consider relaxing the implicit `Sized` restriction: `+  ?Sized`
  |            |
  |            required by this bound in `generic`
  |
  = help: the trait `std::marker::Sized` is not implemented for `dyn std::io::Write`
  = note: to learn more, visit <https://doc.rust-lang.net.cn/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `error-messages`.

To learn more, run the command again with --verbose.

A terminal screenshot of the 1.43.0 error message.

第二个示例(帮助)
fn main() {
    let s = "".to_owned();
    println!("{:?}", s.find("".to_owned()));
}
1.2.0 错误消息
   Compiling error-messages v0.1.0 (file:///Users/ep/src/rust/error-messages)
src/lib.rs:3:24: 3:43 error: the trait `core::ops::FnMut<(char,)>` is not implemented for the type `collections::string::String` [E0277]
src/lib.rs:3     println!("{:?}", s.find("".to_owned()));
                                    ^~~~~~~~~~~~~~~~~~~
note: in expansion of format_args!
<std macros>:2:25: 2:56 note: expansion site
<std macros>:1:1: 2:62 note: in expansion of print!
<std macros>:3:1: 3:54 note: expansion site
<std macros>:1:1: 3:58 note: in expansion of println!
src/lib.rs:3:5: 3:45 note: expansion site
src/lib.rs:3:24: 3:43 error: the trait `core::ops::FnOnce<(char,)>` is not implemented for the type `collections::string::String` [E0277]
src/lib.rs:3     println!("{:?}", s.find("".to_owned()));
                                    ^~~~~~~~~~~~~~~~~~~
note: in expansion of format_args!
<std macros>:2:25: 2:56 note: expansion site
<std macros>:1:1: 2:62 note: in expansion of print!
<std macros>:3:1: 3:54 note: expansion site
<std macros>:1:1: 3:58 note: in expansion of println!
src/lib.rs:3:5: 3:45 note: expansion site
error: aborting due to 2 previous errors
Could not compile `error-messages`.

To learn more, run the command again with --verbose.

A terminal screenshot of the 1.2.0 error message.

1.43.0 错误消息
   Compiling error-messages v0.1.0 (/Users/ep/src/rust/error-messages)
error[E0277]: expected a `std::ops::FnMut<(char,)>` closure, found `std::string::String`
 --> src/lib.rs:3:29
  |
3 |     println!("{:?}", s.find("".to_owned()));
  |                             ^^^^^^^^^^^^^
  |                             |
  |                             expected an implementor of trait `std::str::pattern::Pattern<'_>`
  |                             help: consider borrowing here: `&"".to_owned()`
  |
  = note: the trait bound `std::string::String: std::str::pattern::Pattern<'_>` is not satisfied
  = note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `std::string::String`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `error-messages`.

To learn more, run the command again with --verbose.

A terminal screenshot of the 1.43.0 error message.

第三个示例(借用检查器)
fn main() {
    let mut x = 7;
    let y = &mut x;

    println!("{} {}", x, y);
}
1.2.0 错误消息
   Compiling error-messages v0.1.0 (file:///Users/ep/src/rust/error-messages)
src/lib.rs:5:23: 5:24 error: cannot borrow `x` as immutable because it is also borrowed as mutable
src/lib.rs:5     println!("{} {}", x, y);
                                   ^
note: in expansion of format_args!
<std macros>:2:25: 2:56 note: expansion site
<std macros>:1:1: 2:62 note: in expansion of print!
<std macros>:3:1: 3:54 note: expansion site
<std macros>:1:1: 3:58 note: in expansion of println!
src/lib.rs:5:5: 5:29 note: expansion site
src/lib.rs:3:18: 3:19 note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x` until the borrow ends
src/lib.rs:3     let y = &mut x;
                              ^
src/lib.rs:6:2: 6:2 note: previous borrow ends here
src/lib.rs:1 fn main() {
src/lib.rs:2     let mut x = 7;
src/lib.rs:3     let y = &mut x;
src/lib.rs:4
src/lib.rs:5     println!("{} {}", x, y);
src/lib.rs:6 }
             ^
error: aborting due to previous error
Could not compile `error-messages`.

To learn more, run the command again with --verbose.

A terminal screenshot of the 1.2.0 error message.

1.43.0 错误消息
   Compiling error-messages v0.1.0 (/Users/ep/src/rust/error-messages)
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
 --> src/lib.rs:5:23
  |
3 |     let y = &mut x;
  |             ------ mutable borrow occurs here
4 |
5 |     println!("{} {}", x, y);
  |                       ^  - mutable borrow later used here
  |                       |
  |                       immutable borrow occurs here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0502`.
error: could not compile `error-messages`.

To learn more, run the command again with --verbose.

A terminal screenshot of the 1.43.0 error message.

来自团队的引言

当然,我们无法涵盖所有发生的更改。因此,我们联系了一些团队,询问他们最自豪的哪些更改。

对于 rustdoc,大事是

  • 为 blanket 实现自动生成的文档
  • 搜索本身及其优化(最后一个是将其转换为 JSON)
  • 能够更准确地测试文档代码块“compile_fail、should_panic、allow_fail”
  • 文档测试现在生成为它们自己的独立二进制文件。

— Guillaume Gomez (rustdoc)

Rust 现在拥有基线 IDE 支持!在 IntelliJ Rust、RLS 和 rust-analyzer 之间,我认为大多数用户应该能够为他们选择的编辑器找到“不糟糕”的体验。五年前,“编写 Rust”意味着使用老式的 Vim/Emacs 设置。

— Aleksey Kladov (IDE 和编辑器)

对我来说,那就是:为流行的嵌入式架构添加一流的支持,并实现一个不断发展的生态系统,使使用 Rust 进行微控制器开发成为一种轻松、安全且有趣的体验。

— Daniel Egger (嵌入式 WG)

发布团队从(大约)2018 年初才开始组建,但即使在那段时间里,我们也仅仅在 rust-lang/rust 中就提交了约 40000 次代码,而稳定版没有出现任何重大回归。

考虑到我们改进编译器和标准库的速度之快,我认为这真的很令人印象深刻(当然,发布团队并不是唯一的贡献者)。总的来说,我发现发布团队在管理日益增长的问题跟踪器流量、提交的 PR 等方面做得非常出色。

— Mark Rousskov (发布)

在过去的三年里,我们成功地将 Miri 从一个实验性的解释器转变为一个实用的工具,用于探索语言设计和查找真实代码中的错误——将 PL 理论与实践完美结合。在理论方面,我们有 堆叠借用,这是迄今为止 Rust 别名模型最具体的提案。在实践方面,虽然最初只有我们检查了 Miri 中的几个关键库,但最近我们看到越来越多的人使用 Miri 来 查找和修复他们自己的板条箱和依赖项中的错误,以及类似的贡献者增加,例如通过添加对文件系统访问、展开和并发性的支持来改进 Miri。

— Ralf Jung (Miri)

如果让我选出我最自豪的一件事,那就是非词法生命周期 (NLL) 的工作。这不仅是因为我认为它对 Rust 的可用性产生了重大影响,还因为我们通过组建 NLL 工作组来实现它的方式。这个工作组吸引了许多优秀的贡献者,其中许多人至今仍在为编译器工作。开源的最佳体现!

— Niko Matsakis (语言)

社区

在过去的五年里,随着语言的不断变化和发展,其社区也发生了很大的变化。Rust 中出现了许多优秀的项目,Rust 在生产环境中的应用也呈指数级增长。我们想分享一些关于 Rust 发展程度的统计数据。

  • 在过去的四年里,Rust 在 Stack Overflow 开发者调查中一直被评为 "最受欢迎的编程语言",自 1.0 版本发布以来一直如此。
  • 仅今年一年,我们就提供了超过 2.25 PB(1PB = 1000 TB)的不同版本的编译器、工具和文档!
  • 在同一时间,我们向 crates.io 提供了超过 170 TB 的板条箱,约 18 亿次请求,与去年相比,每月流量翻了一番。

当 Rust 1.0 发布时,你可以用一只手数出在生产环境中使用它的公司数量。如今,它被数百家科技公司使用,其中包括苹果、亚马逊、Dropbox、Facebook、谷歌和微软等一些最大的科技公司,它们选择在项目中使用 Rust,因为它具有性能、可靠性和生产力。

结论

显然,我们无法涵盖自 2015 年以来 Rust 发生的所有变化或改进。你最喜欢的变化或新的 Rust 项目是什么?欢迎在 我们的 Discourse 论坛 上发布你的答案和讨论。

最后,我们要感谢所有为 Rust 做出贡献的人,无论你是贡献了一个新功能还是修复了一个错别字,你的工作都让 Rust 成为今天这个令人惊叹的项目。我们迫不及待地想看看 Rust 及其社区将如何继续发展和变化,以及你们将在未来十年用 Rust 构建什么!