考虑到世界上正在发生的一切,您可能会忘记,截至今天,我们发布 1.0 版本已经五年了!Rust 在过去的五年里发生了很大的变化,因此我们想回顾一下自该语言稳定以来我们所有贡献者的工作。
Rust 是一种通用的编程语言,它使每个人都能够构建可靠和高效的软件。Rust 可以构建为在堆栈中的任何位置运行,无论是作为操作系统的内核还是您的下一个 Web 应用程序。它完全由一个开放且多元化的个人社区构建,主要是志愿者,他们慷慨地捐出时间和专业知识,以帮助使 Rust 成为今天的样子。
自 1.0 以来的重大变化
2015
1.2 — 并行代码生成:编译时间改进是 Rust 每个版本的一个重要主题,很难想象曾经有一段时间 Rust 根本没有并行代码生成。
1.3 — Rustonomicon:我们首次发布了出色的“Rustonomicon”,这是一本探讨 Unsafe Rust 及其周围主题的书,并且已成为任何想要学习和理解该语言最难方面之一的人的绝佳资源。
1.4 — Windows MSVC Tier 1 支持:第一个 Tier 1 平台推广是使用 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
crate 类型允许将 Rust 编译为 C 动态库,使您能够将您的 Rust 项目嵌入到任何支持 C ABI 的系统中。Rust 在用户中最成功的案例之一是能够用 Rust 编写他们系统的一小部分关键部分,并无缝集成到更大的代码库中,现在这比以往任何时候都更容易。
1.12 — Cargo 工作区:工作区允许您组织多个 Rust 项目并共享同一个锁文件。工作区在构建大型多 crate 级别项目方面非常宝贵。
1.13 — 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 的第一个版本,您可以使用像 serde
或 diesel
的派生宏在稳定版上使用。
1.17 — Rustbuild:对于我们语言的贡献者来说,最大的改进之一是将我们的构建系统从最初基于 make
的系统转移到使用 cargo。这使得 rust-lang/rust
对于成员和新手来说更容易构建和贡献项目。
1.20 — 关联常量:以前,常量只能与模块关联。在 1.20 中,我们稳定了 struct、枚举以及重要的 trait 上的关联常量。使其更容易为您的 API 中的类型添加丰富的预设值,例如常见的 IP 地址或有趣的数字。
2018
1.24 — 增量编译:在 1.24 之前,当您在库中进行更改时,rustc 必须重新编译所有代码。现在 rustc 在缓存尽可能多的内容方面更加智能,只需要重新生成所需的内容。
1.26 — impl Trait:添加 impl Trait
为您提供了具有静态调度的好处和性能的富有表现力的动态 API。
1.28 — 全局分配器:以前您只能使用 Rust 提供的分配器。使用全局分配器 API,您现在可以将分配器自定义为适合您需要的分配器。这是启用 alloc
库创建的重要一步,它是标准库的另一个子集,仅包含需要像 Vec
或 String
这样的分配器的 std 部分。现在比以往任何时候都更容易在各种系统上使用标准库的更多部分。
1.31 — 2018 版:2018 版的发布是我们自 1.0 以来最大的版本,它以完全向后兼容的方式添加了一系列语法更改和对 Rust 编写的改进,允许使用不同版本构建的库无缝地协同工作。
- 非词法生命周期 对 Rust 借用检查器的巨大改进,使其能够接受更多可验证的安全代码。
- 模块系统改进 对我们如何定义和使用模块进行了大规模的用户体验改进。
- 常量函数 常量函数允许您在编译时运行和评估 Rust 代码。
- Rustfmt 1.0 专门为 Rust 构建的新代码格式化工具。
- Clippy 1.0 Rust 的 linter,用于捕获常见错误。Clippy 使您更容易确保您的代码不仅安全而且正确。
- Rustfix 随着所有语法更改,我们知道我们希望提供工具来尽可能简化过渡。现在,当 Rust 的语法需要更改时,只需运行
cargo fix
即可解决。
2019
1.34 — 替代 Crate 注册表:随着 Rust 在生产中的使用越来越多,越来越需要能够在非公共空间中托管和使用您的项目,虽然 cargo 一直允许远程 git 依赖项,但使用替代注册表,您的组织可以轻松构建和共享您自己的 crate 注册表,该注册表可以在您的项目中使用,就像它们在 crates.io 上一样。
1.39 — Async/Await:用于处理 Future 的 async/await 关键字的稳定化是使 Rust 中的异步编程成为一等公民的主要里程碑之一。即使在发布仅六个月后,Rust 中的异步编程也已经发展成为一个多样化且高性能的生态系统。
2020
1.42 — 子切片模式:虽然不是最大的变化,但添加 ..
(rest)模式是一个期待已久的质量生活功能,它极大地提高了切片模式匹配的表现力。
错误诊断
我们没有过多提及的一件事是自 1.0 以来 Rust 的错误消息和诊断的改进程度。现在查看旧的错误消息感觉就像在看一种不同的语言。
我们突出显示了几个例子,这些例子最好地展示了我们在向用户展示他们犯错的地方以及重要的是帮助他们理解为什么它不起作用并教他们如何修复它方面所做的改进。
第一个例子(特性)
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.
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 <http://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.
第二个例子(帮助)
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.
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.
第三个例子(借用检查器)
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.
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.
来自团队的引言
当然,我们无法涵盖所有发生的变化。因此,我们联系并询问了一些我们的团队,他们最自豪的变化是什么
对于 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理论和实践的完美结合。在理论方面,我们有Stacked Borrows,这是迄今为止最具体的Rust别名模型提案。在实践方面,虽然最初只有少数关键库由我们使用Miri进行检查,但最近我们看到越来越多的人使用Miri来发现和修复他们自己的 crates 和依赖项中的错误,并且有类似的贡献者加入改进Miri,例如添加对文件系统访问、展开和并发的支持。
— Ralf Jung (Miri)
如果一定要选一件我最引以为豪的事情,那就是关于非词法生命周期(NLL)的工作。这不仅是因为我认为它极大地提高了 Rust 的可用性,还因为我们通过组建 NLL 工作组的方式实现了它。这个工作组引入了许多优秀的贡献者,他们中的许多人今天仍然在从事编译器方面的工作。开源的最好体现!
— Niko Matsakis (语言)
社区
正如该语言在过去五年中发生了很大变化和增长一样,它的社区也是如此。已经有许多很棒的项目是用 Rust 编写的,并且 Rust 在生产中的应用呈指数级增长。我们想分享一些关于 Rust 增长的统计数据。
- 自 1.0 版本发布以来,Rust 在过去四次 Stack Overflow 开发者调查中每年都被评为“最受欢迎的编程语言”。
- 仅今年一年,我们就提供了超过 2.25 PB (1PB = 1,000 TB) 不同版本的编译器、工具和文档!
- 在同一时间段内,我们在 crates.io 上为大约 18 亿次请求提供了超过 170TB 的 crates,与去年相比,月流量翻了一番。
当 Rust 达到 1.0 版本时,你可以用一只手就数得清在生产环境中使用它的公司数量。如今,数百家科技公司正在使用它,其中一些最大的科技公司,如 Apple、Amazon、Dropbox、Facebook、Google 和 Microsoft,都选择在他们的项目中使用 Rust,因为它具有高性能、可靠性和生产力。
结论
显然,我们无法涵盖自 2015 年以来 Rust 的所有变化或改进。您最喜欢的变化或最喜欢的新 Rust 项目是什么?请在我们的 Discourse 论坛上发布您的答案和讨论。
最后,我们要感谢所有为 Rust 做出贡献的人,无论您是贡献了一个新功能还是修复了一个错别字,您的工作都让 Rust 成为了今天如此出色的项目。我们迫不及待地想看看 Rust 及其社区将如何继续发展和变化,并看看大家在未来十年将用 Rust 构建什么!