发布 Rust 1.13

2016 年 11 月 10 日 · Rust 核心团队

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

一如既往,您可以从我们网站的相应页面安装 Rust 1.13.0,并在 GitHub 上查看1.13.0 的详细发行说明。此版本共合入了 1448 个补丁。

这是 Rust 忙碌的一个季度。我们连续举办了三场 Rust 大会,RustConfRustFestRust Belt Rust。很高兴能亲眼见到这么多 Rustaceans,其中有些是第一次见!我们一直在深入思考未来,制定 2017 年路线图,并构建用户告诉我们他们需要的工具

即使有这么多事情发生,我们还是发布了一个充满有趣新功能的新版本。

1.13 稳定版包含哪些内容

1.13 版本包含多项语言扩展,包括期待已久的 ? 运算符、编译时间的改进、Cargo 和标准库的微小功能增强。此版本还包括许多贡献者对文档和错误报告进行的许多小改进,这些改进在发行说明中并未单独提及。

此版本包含 Cargo 的重要安全更新,Cargo 依赖于 curl 和 OpenSSL,它们最近都发布了安全更新。更多信息请参阅 curl 7.51.0OpenSSL 1.0.2j 的各自公告。

? 运算符

Rust 新增了一个运算符 ?,它通过减少视觉上的干扰,使错误处理更加愉快。它通过解决一个简单的问题来实现这一点。例如,假设我们有一些从文件读取数据的代码

fn read_username_from_file() -> Result<String, io::Error> {
    let f = File::open("username.txt");

    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut s = String::new();

    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

这段代码有两个可能失败的路径:打开文件和从中读取数据。如果其中任何一个失败,我们希望从 read_username_from_file 返回一个错误。这样做需要对 I/O 操作的结果进行 match。然而,在这种仅将错误向调用栈上传播的简单情况下,match 只是样板代码——每次都以相同的模式写出来,并不能给读者提供太多有用的信息。

使用 ?,上面的代码看起来像这样

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("username.txt")?;
    let mut s = String::new();

    f.read_to_string(&mut s)?;

    Ok(s)
}

? 是我们之前编写的整个 match 语句的缩写。换句话说,? 应用于 Result 值,如果它是 Ok,则解封并给出内部值。如果它是 Err,则从当前函数返回。从视觉上看,它更加直接。现在我们不再使用整个 match 语句,而是只用单个 "?" 字符来表示我们正在以标准方式处理错误,即通过将它们传递给调用栈的上层。

经验丰富的 Rustaceans 可能认出这与 Rust 1.0 以来就有的 try! 宏相同。事实上,它们是相同的。在 1.13 之前,read_username_from_file 可以这样实现

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = try!(File::open("username.txt"));
    let mut s = String::new();

    try!(f.read_to_string(&mut s));

    Ok(s)
}

那么既然已经有了宏,为什么还要扩展语言呢?原因有很多。首先,try! 被证明非常有用,并且在地道的 Rust 代码中经常使用。它被如此频繁地使用,我们认为值得拥有一个更简洁的语法。这种演变是一个强大的宏系统的巨大优势之一:可以在不修改语言本身的情况下对语言语法的推测性扩展进行原型设计和迭代,反过来,事实证明特别有用的宏可以指出语言缺失的功能。这种从 try!? 的演变就是一个很好的例子。

try! 需要一个更简洁语法的原因之一是,当连续多次调用 try! 时,它显得非常笨重。考虑

try!(try!(try!(foo()).bar()).baz())

与之相对的是

foo()?.bar()?.baz()?

第一个从视觉上很难快速浏览,并且每一层错误处理都会在表达式前加上一个额外的 try! 调用。这使得不重要的错误传播受到了过多的关注,遮蔽了主要代码路径,在此示例中是对 foobarbaz 的调用。这种带有错误处理的方法链在构建器模式等情况下会出现。

最后,专门的语法将来可以更容易地生成专门针对 ? 的更友好的错误消息,而对于宏展开的代码通常很难生成友好的错误消息(尽管在此版本中,? 的错误消息仍有改进空间)。

尽管这是一个小功能,但到目前为止我们的经验表明,? 感觉是对旧的 try! 宏的坚实的易用性改进。这是 Rust 将继续获得的渐进式、生活质量改进的良好范例,打磨我们已经强大的基础语言的粗糙之处。

RFC 243 中阅读更多关于 ? 的信息。

性能改进

最近,对编译器性能给予了大量关注。此版本有好消息,未来还会有更多改进。

Mark Simulacrum 和 Nick Cameron 一直在完善 perf.rust-lang.org,这是我们跟踪编译器性能的工具。它定期在专用硬件上运行 rustc-benchmarks 套件,并跟踪结果随时间的变化。该工具记录编译器每个阶段的结果,并被编译器开发者用来缩小性能回归的提交范围。它是我们工具箱的重要组成部分!

我们可以使用这个工具查看 1.13 开发周期内的性能图表,如下所示。这个周期涵盖了从 8 月 16 日到 9 月 29 日(图表从 8 月 25 日开始,并经过一些过滤以消除虚假、不完整或令人困惑的结果)。似乎有一些显著的下降,这些下降在相应的统计页面上进行了量化。


Performance graph


图表中所示的显著改进(发生在 9 月 1 日)来自于 Niko 对翻译过程中缓存规范化投影的优化。也就是说,在生成 LLVM IR 时,编译器不再每次需要时重新计算关联类型的具体实例,而是重用之前计算的值。这项优化并非对所有代码库都有效,但在表现出特定模式的代码库中,例如 futures-rs,其中debug 模式的构建时间提高了高达 40%,您将注意到差异。

另一项并非对所有 crate 都有效但对某些 crate 影响很大的优化来自 Michael Woerister,它改进了导出许多 inline 函数的 crate 的编译时间。当一个函数被标记为 #[inline] 时,除了将其翻译供当前 crate 使用外,编译器还会将其 MIR 表示存储在 crate 的 rlib 中,并在每个调用它的 crate 中将其翻译成 LLVM IR。Michael 所做的优化事后看来显而易见:在某些情况下,inline 函数仅供其他 crate 使用,从未在定义它们的 crate 中被调用;因此,编译器不需要在定义它们的 crate 中翻译 inline 函数的代码,除非它们被直接调用。这节省了 rustc 将函数转换为 LLVM IR 以及 LLVM 优化并转换为机器代码的成本。

在某些情况下,这带来了显著的改进。ndarray crate 的构建时间提高了 50%,而在(未发布的)winapi 0.3 crate 中,rustc 现在完全不生成机器代码。

等等,还有更多!Nick Nethercote 也将他的精力投入到编译器性能上,专注于分析和微优化。此版本包含了他工作的几项成果,1.14 版本中还有更多正在进行中。

其他值得注意的变更

此版本包含 Cargo 的重要安全更新,Cargo 依赖于 curl 和 OpenSSL,它们最近都发布了安全更新。更多信息请参阅 curl 7.51.0OpenSSL 1.0.2j 的各自公告。

宏现在可以在类型位置使用 (RFC 873),并且属性可以应用于语句 (RFC 16)

// Use a macro to name a type
macro_rules! Tuple {
    { $A:ty,$B:ty } => { ($A, $B) }
}

let x: Tuple!(i32, i32) = (1, 2);
// Apply a lint attribute to a single statement
#[allow(non_snake_case)]
let BAD_STYLE = List::new();

内联 drop flags 已被移除。以前,在条件移动的情况下,编译器会在结构体中内联存储一个“drop flag”(增加其大小)来跟踪是否需要 drop。这意味着某些结构体会占用一些意外的额外空间,这会干扰带有析构器的类型通过 FFI 传递等操作。对于没有条件移动的代码来说,这也是空间的浪费。在 1.12 中,MIR 成为默认设置,这为许多改进奠定了基础,包括摆脱这些内联 drop flags。现在,drop flags 存储在需要它们的函数的栈帧的额外槽位中。

1.13 在使用硬件浮点数的 ARM 目标的代码生成中包含一个严重错误(这包括大多数 ARM 目标)。Rust 中的 ARM 目标目前处于我们的第二支持层级,因此此错误未被认定会阻止发布。由于 1.13 包含安全更新,强烈建议必须针对 ARM 的用户使用 1.14 beta 版,其中很快将修复 ARM 错误。

语言稳定性

库稳定性

Cargo 功能

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

1.13.0 的贡献者

共有 155 位个人为 1.13.0 做出了贡献。非常感谢大家!

  • Aaron Gallagher
  • Abhishek Kumar
  • aclarry
  • Adam Medziński
  • Ahmed Charles
  • Aleksey Kladov
  • Alexander von Gluck IV
  • Alexandre Oliveira
  • Alex Burka
  • Alex Crichton
  • Amanieu d'Antras
  • Amit Levy
  • Andrea Corradi
  • Andre Bogus
  • Andrew Cann
  • Andrew Cantino
  • Andrew Lygin
  • Andrew Paseltiner
  • Andy Russell
  • Ariel Ben-Yehuda
  • arthurprs
  • Ashley Williams
  • athulappadan
  • Austin Hicks
  • bors
  • Brian Anderson
  • c4rlo
  • Caleb Jones
  • CensoredUsername
  • cgswords
  • changchun.fan
  • Chiu-Hsiang Hsu
  • Chris Stankus
  • Christopher Serr
  • Chris Wong
  • clementmiao
  • Cobrand
  • Corey Farwell
  • Cristi Cobzarenco
  • crypto-universe
  • dangcheng
  • Daniele Baracchi
  • DarkEld3r
  • David Tolnay
  • Dustin Bensing
  • Eduard Burtescu
  • Eduard-Mihai Burtescu
  • Eitan Adler
  • Erik Uggeldahl
  • Esteban Küber
  • Eugene Bulkin
  • Eugene R Gonzalez
  • Fabian Zaiser
  • Federico Ravasio
  • Felix S. Klock II
  • Florian Gilcher
  • Gavin Baker
  • Georg Brandl
  • ggomez
  • Gianni Ciccarelli
  • Guillaume Gomez
  • Jacob
  • jacobpadkins
  • Jake Goldsborough
  • Jake Goulding
  • Jakob Demler
  • James Duley
  • James Miller
  • Jared Roesch
  • Jared Wyles
  • Jeffrey Seyfried
  • JessRudder
  • Joe Neeman
  • Johannes Löthberg
  • John Firebaugh
  • johnthagen
  • Jonas Schievink
  • Jonathan Turner
  • Jorge Aparicio
  • Joseph Dunne
  • Josh Triplett
  • Justin LeFebvre
  • Keegan McAllister
  • Keith Yeung
  • Keunhong Lee
  • king6cong
  • Knight
  • knight42
  • Kylo Ginsberg
  • Liigo
  • Manish Goregaokar
  • Mark-Simulacrum
  • Matthew Piziak
  • Matt Ickstadt
  • mcarton
  • Michael Layne
  • Michael Woerister
  • Mikhail Modin
  • Mohit Agarwal
  • Nazım Can Altınova
  • Neil Williams
  • Nicholas Nethercote
  • Nick Cameron
  • Nick Platt
  • Niels Sascha Reedijk
  • Nikita Baksalyar
  • Niko Matsakis
  • Oliver Middleton
  • Oliver Schneider
  • orbea
  • Panashe M. Fundira
  • Patrick Walton
  • Paul Fanelli
  • philipp
  • Phil Ruffwind
  • Piotr Jawniak
  • pliniker
  • QuietMisdreavus
  • Rahul Sharma
  • Richard Janis Goldschmidt
  • Scott A Carr
  • Scott Olson
  • Sean McArthur
  • Sebastian Ullrich
  • Sébastien Marie
  • Seo Sanghyeon
  • Sergio Benitez
  • Shyam Sundar B
  • silenuss
  • Simonas Kazlauskas
  • Simon Sapin
  • Srinivas Reddy Thatiparthy
  • Stefan Schindler
  • Stephan Hügel
  • Steve Klabnik
  • Steven Allen
  • Steven Fackler
  • Terry Sun
  • Thomas Garcia
  • Tim Neumann
  • Tobias Bucher
  • Tomasz Miąsko
  • trixnz
  • Tshepang Lekhonkhobe
  • Ulrich Weigand
  • Ulrik Sverdrup
  • Vadim Chugunov
  • Vadim Petrochenkov
  • Vanja Cosic
  • Vincent Esche
  • Wesley Wiser
  • William Lee
  • Ximin Luo
  • Yossi Konstantinovsky
  • zjhmale