宣布 Rust 1.21

2017年10月12日 · Rust 核心团队

Rust 团队很高兴宣布 Rust 的最新版本 1.21.0 发布。Rust 是一门专注于安全、速度和并发的系统编程语言。

如果您已经安装了旧版本的 Rust,获取 Rust 1.21 和以下步骤一样简单:

$ rustup update stable

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

1.21.0 stable 版本有什么新内容

此版本包含一些非常细微但实用(nice-to-have)的功能,以及一些新的文档。

首先,对字面量(literals)做了一个小改动。考虑如下代码:

let x = &5;

在 Rust 中,这段代码等同于:

let _x = 5;
let x = &_x;

也就是说,这里的 5 会存储在栈(stack)上,或者可能存储在寄存器(registers)中。x 将是对它的引用(reference)。

然而,考虑到它是一个字面整数,它不一定必须像这样是局部的。想象一下我们有一个接受 'static 参数的函数,例如 std::thread::spawn。你可能会这样使用 x

use std::thread;

fn main() {
    let x = &5;

    thread::spawn(move || {
        println!("{}", x);
    });

}

在之前的 Rust 版本中,这段代码会编译失败:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:4:14
   |
4  |     let x = &5;
   |              ^ does not live long enough
...
10 | }
   | - temporary value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

因为 5 是局部的,它的借用(borrow)也是局部的,这不满足 spawn 的要求。

然而,如果你在 Rust 1.21 上编译这段代码,它会工作。为什么?因为如果被引用的东西可以放入 static,我们可以将 let x = &5; 解糖(de-sugar)成这样:

static FIVE: i32 = 5;

let x = &FIVE;

在这里,由于 FIVEstatic 的,x 就是一个 &'static i32。因此,在遇到这种情况时,Rust 现在就会这样做。有关详细信息,请参阅 RFC 1414,该 RFC 于今年一月被接受,但早在 2015 年 12 月就开始了!

我们现在在生成代码时并行运行 LLVM,这应该会降低峰值内存使用量。

RLS 现在可以通过 rustup 安装,通过运行 rustup component add rls-preview 命令。通常,许多有用的 Rust 开发者工具,例如 RLS、Clippy 和 rustfmt,需要 nightly 版本的 Rust;这是让它们在 stable 版本的 Rust 上工作的第一步。请试用此预览版,未来你会听到更多关于这些计划的信息。

最后,一些文档改进。首先,如果你访问std::os 的文档(它包含操作系统特定的功能),你现在会看到不仅仅是 linux(我们构建文档所用的平台)。我们一直很遗憾托管版本的文档是 Linux 特有的;这是纠正这种情况的第一步。这特定于标准库,并非普遍适用;我们希望未来能进一步改进这一点。

接下来,Cargo 的文档正在迁移!历史上,Cargo 的文档托管在 doc.crates.io 上,它不遵循发布列车(release train)模型,尽管 Cargo 本身是遵循的。这导致了一种情况:一个功能可能在 Cargo nightly 中落地,文档也随之更新,但接下来的长达十二周内,用户会以为它应该工作,但实际上却不行。https://doc.rust-lang.net.cn/cargo 将成为 Cargo 文档的新主页,不过目前,这个 URL 会重定向到 doc.crates.io。未来的版本会将 Cargo 的文档迁移过来,届时,doc.crates.io 将重定向到 doc.rust-lang.org/cargo。Cargo 的文档早就需要改进更新了,因此,未来请期待更多关于 Cargo 文档的通用消息!

最后,到目前为止,rustdoc 还没有任何文档。现在这已得到解决,随着一本新的 “rustdoc Book” 的出现,它位于 https://doc.rust-lang.net.cn/rustdoc。这些文档目前相当基础,但我们会随着时间逐步改进它们。

查看详细发布说明了解更多信息。

标准库稳定化

这个版本没有太多稳定化,但有一个非常棒的“生活质量”改进:由于缺乏类型级别的整数(type-level integers),数组只支持尺寸最大为 32 的各种 trait。现在这已针对 Clone trait 修复,在类型是 Copy 但不是 Clone 时,这有时也会导致很多内部编译器错误(ICE)。对于其他 trait,一项关于类型级别整数的 RFC 最近被接受,这可能有助于解决这种情况。然而,这项更改尚未实现,不过目前正在进行前期准备工作。

接下来,Iterator::for_each 已稳定,让你可以在不需要 for 循环的情况下,消费迭代器来产生副作用。

// old
for i in 0..10 {
    println!("{}", i);
}

// new
(0..10).for_each(|i| println!("{}", i));

使用哪种取决于你的具体情况;在上面的示例中,for 循环非常直观。但当你将多个迭代器串联起来时,for_each 版本有时会更清晰。请考虑以下情况:

// old
for i in (0..100).map(|x| x + 1).filter(|x| x % 2 == 0) {
    println!("{}", i);
}

// new
(0..100)
    .map(|x| x + 1)
    .filter(|x| x % 2 == 0)
    .for_each(|i| println!("{}", i));

Rc<T>Arc<T> 现在实现了 From<&[T]> where T: Clone, From<str>, From<String>, From<Box<T>> where T: ?Sized, 以及 From<Vec<T>>

Ord trait 上的 maxmin 函数现在已稳定。

needs_drop intrinsic 现在已稳定。

最后,std::mem::discriminant 已稳定,让你可以在不需要 match 语句的情况下,查看 enum 实例是哪个变体。

查看详细发布说明了解更多信息。

Cargo 特性

除了上面列出的文档特性之外,Cargo 在这个版本中获得了一个主要特性:[patch]。根据 RFC 1969 设计,你 Cargo.toml 文件中的 [patch] 部分可以在你想要覆盖依赖图的特定部分时使用。我们还有一个功能 [replace],它具有类似的功能。在许多方面,[patch] 是新的 [replace],虽然我们没有计划废弃或移除 [replace],但现在你应该使用 [patch] 代替 [replace]

那么它看起来是什么样的?假设我们有一个 Cargo.toml 文件如下所示:

[dependencies]
foo = "1.2.3"

此外,我们的 foo crate 依赖于 bar crate,并且我们在 bar 中发现了一个 bug。为了测试它,我们会下载 bar 的源代码,然后更新我们的 Cargo.toml 文件。

[dependencies]
foo = "1.2.3"

[patch.crates-io]
bar = { path = '/path/to/bar' }

现在,当你运行 cargo build 时,它将使用本地版本的 bar,而不是 foo 所依赖的来自 crates.io 的那个版本。

有关更多详细信息,请参阅文档

此外

查看详细发布说明了解更多信息。

1.21.0 版本的贡献者

许多人共同努力创造了 Rust 1.21。没有你们所有人,我们不可能做到这一点。感谢你们!