宣布 Rust 1.36.0

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

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

如果您通过 rustup 安装了以前版本的 Rust,获取 Rust 1.36.0 就像

$ rustup update stable

如果您还没有,您可以从我们网站上的相应页面获取 rustup,并查看 GitHub 上1.36.0 的详细发布说明

1.36.0 稳定版中的内容

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

Future 来了!

在 Rust 1.36.0 中,期待已久的 Future 特性已稳定

通过这种稳定,我们希望为重要的箱、库和生态系统提供时间来为 async / .await 做准备,我们将在将来告诉您更多关于它们的信息。

alloc 箱已稳定

在 1.36.0 之前,标准库由 stdcoreproc_macro 箱组成。core 箱提供了核心功能,例如 IteratorCopy,并且可以在 #![no_std] 环境中使用,因为它没有施加任何要求。同时,std 箱提供了 Box<T> 和操作系统功能等类型,但需要一个全局分配器和其他操作系统功能作为回报。

从 Rust 1.36.0 开始,std 中依赖于全局分配器的部分(例如 Vec<T>)现在可以在 alloc 箱中使用。然后,std 箱重新导出这些部分。虽然使用 alloc#![no_std] 二进制文件仍然需要 nightly Rust,但 #![no_std] 箱可以在稳定的 Rust 中使用 alloc 箱。同时,没有 #![no_std] 的普通二进制文件可以依赖于此类库箱。我们希望这将有助于在稳定支持使用 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 借用检查器会接受的代码,我们将发出警告而不是错误。请查看此列表,其中列出了受影响的公共箱。

要详细了解 NLL、MIR、修复健全性漏洞的故事以及如果遇到警告可以采取的措施,请阅读Felix Klock 的博客文章

新的 HashMap<K, V> 实现

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

Cargo 中的 --offline 支持

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

在 Rust 1.36 中,一个新的 Cargo 标志已稳定:--offline。该标志会更改 Cargo 的依赖项解析算法,使其仅使用本地缓存的依赖项。当所需的箱在脱机状态下不可用时,并且需要网络访问,Cargo 将退出并显示错误。要预先填充本地缓存以准备脱机使用,请使用 cargo fetch 命令,该命令会下载项目所需的所有依赖项。

要详细了解 --offlinecargo fetch,请阅读Nick Cameron 的博客文章

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

库更改

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

此外,一些 API 已变为 const

新的 API 已稳定,包括

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

其他变更

详细的 1.36.0 版本发布说明可用于 RustCargoClippy

1.36.0 贡献者

许多人共同创建了 Rust 1.36.0。没有你们,我们无法做到。 感谢!