Rust 1.36.0 版本发布

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

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

如果您之前通过 rustup 安装了 Rust,那么升级到 Rust 1.36.0 非常简单,只需执行:

$ rustup update stable

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

1.36.0 稳定版的新特性

此版本带来了许多更改,包括 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 之前,标准库由 crate stdcoreproc_macro 组成。core crate 提供了核心功能,例如 IteratorCopy,并且可以在 #![no_std] 环境中使用,因为它不施加任何要求。同时,std crate 提供了诸如 Box<T> 和操作系统功能之类的类型,但需要全局分配器和其他操作系统功能作为回报。

从 Rust 1.36.0 开始,std 中依赖于全局分配器的部分,例如 Vec<T>,现在可以在 alloc crate 中使用。然后 std crate 重新导出这些部分。虽然使用 alloc#![no_std] *二进制文件* 仍然需要 nightly Rust,但 #![no_std] *库* crate 可以在稳定的 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 函数允许您绕过 Rust 的初始化检查,方法是假装您已经初始化了类型为 T 的值,而实际上什么也没做。此函数的主要用途之一是延迟分配数组。

但是,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(Non-Lexical Lifetimes,非词法生命周期),这是对语言的改进,使借用检查器更智能,更用户友好。例如,您现在可以编写:

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> 实现已 替换hashbrown crate 中的实现,该实现基于 SwissTable 设计。虽然接口相同,但 HashMap<K, V> 实现现在 平均速度更快 并且具有更低的内存开销。请注意,与 hashbrown crate 不同,std 中的实现仍然默认使用 SipHash 1-3 哈希算法。

Cargo 中的 --offline 支持

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

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

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

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

库变更

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

此外,许多 API 已被设为 const

新的 API 已变为稳定,包括

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

其他变更

RustCargoClippy 的 1.36.0 详细发布说明已发布。

1.36.0 版本的贡献者

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