宣布 Rust 1.40.0

2019 年 12 月 19 日 · Rust 发布团队

Rust 团队很高兴发布 Rust 的新版本 1.40.0。Rust 是一门赋能所有人构建可靠且高效软件的编程语言。

如果你之前通过 rustup 安装过 Rust,获取 Rust 1.40.0 就像这样简单:

$ rustup update stable

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

1.40.0 stable 版本有哪些内容

Rust 1.40.0 的亮点包括 #[non_exhaustive] 以及对 macros!()#[attribute] 的改进。最后,Rust 2015 版本中的借用检查迁移警告已成为硬错误。有关更多信息,请参阅详细发布说明

#[non_exhaustive] structs、enums 和 variants

假设你是一个名为 alpha 的 crate 的库作者,其中有一个 pub struct Foo。你希望将 alpha::Foo 的字段也设为 pub,但你不确定将来是否会为 Foo 添加更多字段。所以你现在面临一个两难境地:要么将字段设为私有,带来一系列缺点;要么冒着用户依赖确切字段的风险,当你添加新字段时可能会破坏他们的代码。Rust 1.40.0 引入了一种打破僵局的方法:#[non_exhaustive]

属性 #[non_exhaustive] 附加到 structenum 的 variant 上时,将阻止在该 crate 外部的代码构造该 struct 或 variant。为了避免将来出现破坏性更改,其他 crate 也无法对字段进行穷尽匹配。以下示例说明了依赖于 alphabeta 中的错误

// alpha/lib.rs:

#[non_exhaustive]
struct Foo {
    pub a: bool,
}

enum Bar {
    #[non_exhaustive]
    Variant { b: u8 }
}

fn make_foo() -> Foo { ... }
fn make_bar() -> Bar { ... }

// beta/lib.rs:

let x = Foo { a: true }; //~ ERROR
let Foo { a } = make_foo(); //~ ERROR

// `beta` will still compile when more fields are added.
let Foo { a, .. } = make_foo(); //~ OK


let x = Bar::Variant { b: 42 }; //~ ERROR
let Bar::Variant { b } = make_bar(); //~ ERROR
let Bar::Variant { b, .. } = make_bar(); //~ OK
                   // -- `beta` will still compile...

幕后发生的事情是,#[non_exhaustive] structenum variant 的构造函数的可见性降低到 pub(crate),从而阻止了在定义它的 crate 外部的访问。

#[non_exhaustive] 更重要的一个方面可能是它可以附加到 enum 本身。一个取自标准库的例子是 Ordering

#[non_exhaustive]
pub enum Ordering { Relaxed, Release, Acquire, AcqRel, SeqCst }

在此上下文中,#[non_exhaustive] 的目的是确保随着时间的推移可以添加更多 variant。这是通过阻止其他 crate 对 Ordering 进行穷尽模式 match 来实现的。也就是说,编译器会拒绝

match ordering {
    // This is an error, since if a new variant is added,
    // this would suddenly break on an upgrade of the compiler.
    Relaxed | Release | Acquire | AcqRel | SeqCst => {
        /* logic */
    }
}

相反,其他 crate 需要通过添加通配符分支(例如使用 _)来考虑更多 variant 的可能性

match ordering {
    Relaxed | Release | Acquire | AcqRel | SeqCst => { /* ... */ }
    // OK; if more variants are added, nothing will break.
    _ => { /* logic */ }
}

有关 #[non_exhaustive] 属性的更多详细信息,请参阅稳定化报告

宏和属性改进

在 1.40.0 中,我们引入了对宏和属性的几项改进,包括

Rust 2015 版本中,借用检查迁移警告成为硬错误

在 1.35.0 版本中,我们宣布 NLL 已来到 Rust 2015 版本,此前 NLL 已在 Rust 1.31 版本中针对 2018 版本发布。

正如我们当时指出的,旧的借用检查器存在一些可能导致内存不安全性的错误,而 NLL 借用检查器修复了这些错误。由于这些修复会破坏一些稳定代码,我们决定逐步引入错误,通过检查旧的借用检查器是否接受该程序而 NLL 检查器是否拒绝它来判断。在这些情况下,错误会被降级为警告。

上一个版本 Rust 1.39.0 将使用 2018 版本的代码中的这些警告变更为错误。Rust 1.40.0 对使用 2015 版本的用户应用了相同的更改,彻底关闭了这些健全性漏洞。这也使我们能够清理编译器中的旧代码

如果你的构建因为此更改而中断,或者你想了解更多信息,请查阅Niko Matsakis 的博客文章

标准库中更多的 const fn

随着 Rust 1.40.0 的发布,以下函数成为了 const fn

标准库新增内容

在 Rust 1.40.0 中,以下函数和宏已稳定化

其他变化

Rust 1.40.0 版本还有其他变化:查看 RustCargoClippy 中有什么变化。

另请参阅兼容性说明,检查你是否受到这些变化的影响。

1.40.0 的贡献者

许多人齐心协力创建了 Rust 1.40.0。没有你们,我们做不到。感谢大家!