宣布 Rust 1.60.0

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

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

如果您之前已通过 rustup 安装了 Rust,则可以使用以下命令获取 1.60.0

$ rustup update stable

如果您还没有,您可以从我们网站上的相应页面 获取 rustup,并查看 GitHub 上的 1.60.0 的详细发布说明。如果您想通过测试未来版本来帮助我们,您可以考虑更新本地版本以使用 beta 频道 (rustup default beta) 或 nightly 频道 (rustup default nightly)。请 报告您遇到的任何错误!

1.60.0 稳定版中的新内容

基于源代码的代码覆盖率

rustc 中已稳定支持基于 LLVM 的覆盖率检测。您可以通过使用 -Cinstrument-coverage 重新构建代码来尝试此功能,例如:

RUSTFLAGS="-C instrument-coverage" cargo build

之后,您可以运行生成的二进制文件,它将在当前目录中生成一个 default.profraw 文件。(路径和文件名可以通过环境变量覆盖;有关详细信息,请参阅 文档)。

llvm-tools-preview 组件包含用于处理和合并原始配置文件输出(覆盖率区域执行计数)的 llvm-profdata;以及用于报告生成的 llvm-covllvm-cov 将来自 llvm-profdata 的处理后的输出与二进制文件本身结合在一起,因为二进制文件嵌入了一个从计数器到实际源代码区域的映射。

rustup component add llvm-tools-preview
$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-profdata merge -sparse default.profraw -o default.profdata
$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-cov show -Xdemangler=rustfilt target/debug/coverage-testing \
    -instr-profile=default.profdata \
    -show-line-counts-or-regions \
    -show-instantiations

以上命令在简单的 helloworld 二进制文件上会生成以下带注释的报告,显示输入的每一行都被覆盖。

    1|      1|fn main() {
    2|      1|    println!("Hello, world!");
    3|      1|}

有关更多详细信息,请阅读 rustc 手册中的 文档。基本功能是稳定的,将在所有未来的 Rust 版本中以某种形式存在,但具体的输出格式和生成它的 LLVM 工具可能会发生变化。因此,确保您为 llvm-tools-preview 和用于编译代码的 rustc 二进制文件使用相同的版本非常重要。

cargo --timings

Cargo 已稳定支持使用 --timings 标志收集构建信息。

$ cargo build --timings
   Compiling hello-world v0.1.0 (hello-world)
      Timing report saved to target/cargo-timings/cargo-timing-20220318T174818Z.html
    Finished dev [unoptimized + debuginfo] target(s) in 0.98s

该报告也会复制到 target/cargo-timings/cargo-timing.html。关于 Cargo 发布版本的报告已发布 此处。这些报告可以帮助提高构建性能。有关计时报告的更多信息,请参阅 文档

Cargo 功能的新语法

此版本引入了两个新更改,以改进对 Cargo 功能 及其与 可选依赖项 的交互的支持:命名空间依赖项和弱依赖项功能。

Cargo 长期以来一直支持功能以及可选依赖项,如下面的代码片段所示。

[dependencies]
jpeg-decoder = { version = "0.1.20", default-features = false, optional = true }

[features]
# Enables parallel processing support by enabling the "rayon" feature of jpeg-decoder.
parallel = ["jpeg-decoder/rayon"]

此示例中有两点需要注意

  • 可选依赖项 jpeg-decoder 隐式定义了同名的功能。启用 jpeg-decoder 功能将启用 jpeg-decoder 依赖项。
  • "jpeg-decoder/rayon" 语法启用 jpeg-decoder 依赖项以及启用 jpeg-decoder 依赖项的 rayon 功能。

命名空间功能解决了第一个问题。您现在可以在 [features] 表中使用 dep: 前缀来显式引用可选依赖项,而不会将其隐式公开为功能。这使您可以更好地控制如何定义与可选依赖项相对应的功能,包括将可选依赖项隐藏在更具描述性的功能名称后面。

弱依赖项功能解决了第二个问题,即 "optional-dependency/feature-name" 语法始终会启用 optional-dependency。但是,通常您只想在其他功能启用了可选依赖项的情况下才启用可选依赖项上的功能。从 1.60 开始,您可以在 "package-name?/feature-name" 中添加一个 ?,这将仅在其他内容启用了可选依赖项的情况下才启用给定的功能。

例如,假设我们已向我们的库添加了一些序列化支持,并且它需要在一些可选依赖项中启用相应的功能。这可以通过以下方式完成

[dependencies]
serde = { version = "1.0.133", optional = true }
rgb = { version = "0.8.25", optional = true }

[features]
serde = ["dep:serde", "rgb?/serde"]

在此示例中,启用 serde 功能将启用 serde 依赖项。它还会启用 rgb 依赖项的 serde 功能,但前提是其他内容已启用了 rgb 依赖项。

增量编译状态

增量编译已在 1.60 版本中重新启用。Rust 团队继续致力于修复增量中的错误,但目前尚无已知会导致广泛破坏的问题,因此我们选择重新启用增量编译。此外,编译器团队正在继续致力于长期策略,以避免此类问题的再次发生。该过程还处于早期阶段,因此我们目前还没有任何关于这方面的信息可以分享。

Instant 单调性保证

在所有平台上,Instant 将尝试使用一个保证单调行为的 OS API(如果可用)(这在所有一级平台上都是如此)。实际上,这种保证在极少数情况下会被硬件、虚拟化或操作系统错误破坏。为了解决这些错误和不提供单调时钟的平台,Instant::duration_sinceInstant::elapsedInstant::sub 现在会饱和为零。在旧版本的 Rust 中,这会导致恐慌。Instant::checked_duration_since 可用于检测和处理单调性被违反的情况,或 Instant 以错误的顺序相减的情况。

此解决方法掩盖了将较早和较晚的时刻意外交换的编程错误。因此,未来的 Rust 版本可能会在至少这些情况下重新引入恐慌,如果可能且有效的话。

在 1.60 之前,单调性保证是通过 std 中的互斥锁或原子操作提供的,这会导致 Instant::now() 产生巨大的性能开销。此外,恐慌行为意味着 Rust 软件可能会在某些环境中恐慌,这在很大程度上是不可取的,因为该软件的作者可能无法修复或升级他们正在运行的操作系统、硬件或虚拟化系统。此外,在这些环境中引入意外恐慌会降低 Rust 软件的可靠性和可移植性,这比将通常不重要的平台错误暴露给最终用户在单调时钟处理方面更为重要。

稳定的 API

以下方法和特征实现现在已稳定

其他更改

Rust 1.60.0 版本还包含其他更改。查看 RustCargoClippy 中的更改。

1.60.0 版本贡献者

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