发布 Rust 1.36.0

2019 年 7 月 4 日 · Rust 发布团队

Rust 团队很高兴地宣布 Rust 的新版本 1.36.0。Rust 是一种赋予每个人构建可靠且高效软件能力的编程语言。

如果您通过 rustup 安装了 Rust 的早期版本,升级到 Rust 1.36.0 就像下面这样简单:

$ rustup update stable

如果您尚未安装 rustup,可以从我们网站的相应页面获取 rustup,并在 GitHub 上查阅 1.36.0 的详细发布说明

1.36.0 stable 版本包含什么?

此版本带来了许多变化,包括 Future trait、alloc crate、MaybeUninit<T> 类型、Rust 2015 的 NLL、新的 HashMap<K, V> 实现以及 Cargo 中的 --offline 支持的稳定。请继续阅读以了解一些亮点,或参阅详细发布说明以获取更多信息。

Future 来了!

在 Rust 1.36.0 中,期待已久的 Future trait 已经稳定了!

通过这次稳定,我们希望为重要的 crate、库和生态系统争取时间来为 async / .await 做准备,我们将在未来为您带来更多相关信息。

alloc crate 稳定了

在 1.36.0 之前,标准库由 stdcoreproc_macro 这些 crate 组成。core crate 提供了核心功能,例如 IteratorCopy,并且可以在 #![no_std] 环境中使用,因为它不施加任何要求。同时,std crate 提供了像 Box<T> 这样的类型和 OS 功能,但反过来需要全局分配器和其他 OS 能力。

从 Rust 1.36.0 开始,std 中依赖于全局分配器的部分(例如 Vec<T>)现在可以在 alloc crate 中使用。然后 std crate 重新导出这些部分。虽然使用 alloc#![no_std] 二进制文件仍然需要 nightly Rust,但 #![no_std] crate 可以在 stable Rust 中使用 alloc crate。同时,没有 #![no_std] 的普通二进制文件可以依赖于此类库 crate。我们希望这有助于在稳定对使用 alloc#![no_std] 二进制文件的支持之前,促进兼容 #![no_std] 的库生态系统的发展。

如果您是一个仅依赖于某些分配原语即可正常运行的库的维护者,请考虑通过在 lib.rs 文件的顶部使用以下代码来使您的库兼容 #[no_std]

#![no_std]

extern crate alloc;

use alloc::vec::Vec;

使用 MaybeUninit<T> 替代 mem::uninitialized

在 Rust 的早期版本中,mem::uninitialized 函数允许您通过假装已经初始化了类型 T 的值而无需实际操作来绕过 Rust 的初始化检查。该函数的主要用途之一是延迟分配数组。

然而,mem::uninitialized 是一个极其危险的操作,实际上无法正确使用,因为 Rust 编译器假定值已正确初始化。例如,调用 mem::uninitialized::<bool>() 会导致 立即触发 未定义行为,因为从 Rust 的角度来看,未初始化的位既不是 0(表示 false),也不是 1(表示 true)——这是 bool 仅有的两个允许的位模式。

为了补救这种情况,在 Rust 1.36.0 中,类型 MaybeUninit<T> 已经稳定。Rust 编译器会明白它不应该假定 MaybeUninit<T> 是一个正确初始化的 T。因此,您可以更安全地进行渐进式初始化,并在确定 maybe_t: MaybeUninit<T> 包含一个已初始化的 T 时,最终使用 .assume_init()

由于 MaybeUninit<T> 是更安全的替代方案,从 Rust 1.39 开始,函数 mem::uninitialized 将被弃用。

要了解更多关于未初始化内存、mem::uninitializedMaybeUninit<T> 的信息,请阅读Alexis Beingessner 的博客文章。标准库也包含关于 MaybeUninit<T> 的详细文档。

Rust 2015 的 NLL

在 Rust 1.31.0 的发布公告中,我们向您介绍了 NLL(非词法生命周期),这是一个语言改进,使借用检查器更智能、更用户友好。例如,您现在可以编写

fn main() {
    let mut x = 5;
    let y = &x;
    let z = &mut x; // This was not allowed before 1.31.0.
}

在 1.31.0 中,NLL 仅为 Rust 2018 稳定,并承诺将其回迁到 Rust 2015。在 Rust 1.36.0 中,我们很高兴地宣布我们已经做到了!NLL 现在已可用于 Rust 2015。

随着 NLL 在两个版本中都可用,我们离移除旧的借用检查器更近了。然而,旧的借用检查器不幸接受了一些本不应接受的不健全代码。因此,NLL 目前处于“迁移模式”,如果 NLL 借用检查器拒绝了旧的 AST 借用检查器会接受的代码,我们将发出警告而不是错误。请查看此列表,其中包含了受影响的公共 crate。

要了解更多关于 NLL、MIR、修复健全性漏洞的故事以及如果您遇到警告可以怎么做,请阅读Felix Klock 的博客文章

新的 HashMap<K, V> 实现

在 Rust 1.36.0 中,HashMap<K, V> 的实现已经被替换为基于 SwissTable 设计的 hashbrown crate 中的实现。尽管接口相同,但 HashMap<K, V> 实现现在平均更快并且内存开销更低。请注意,与 hashbrown crate 不同,std 中的实现仍然默认为 SipHash 1-3 哈希算法。

Cargo 中的 --offline 支持

在大多数构建过程中,Cargo 不需要与网络交互。然而,有时 Cargo 不得不这样做。例如添加依赖项并需要下载最新的兼容版本时就是如此。但有时网络访问是不可行的,例如在飞机上或隔离的构建环境中。

在 Rust 1.36 中,一个新的 Cargo flag 已经稳定:--offline。该 flag 会改变 Cargo 的依赖解析算法,使其仅使用本地缓存的依赖项。当所需 crate 离线不可用且需要网络访问时,Cargo 将会退出并报错。为了在离线前预填充本地缓存,请使用 cargo fetch 命令,该命令会下载项目所需的所有依赖项。

要了解更多关于 --offlinecargo fetch 的信息,请阅读Nick Cameron 的博客文章

有关 Cargo 其他更改的信息,请参阅详细发布说明

库更改

dbg! 宏现在支持多个参数。

此外,许多 API 已被标记为 const

新的 API 已稳定,包括

其他库更改可在详细发布说明中找到。

其他更改

详细的 1.36.0 发布说明可在 RustCargoClippy 中找到。

1.36.0 的贡献者

许多人共同努力创建了 Rust 1.36.0。没有你们,我们不可能做到。感谢!