发布 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 stable 中有什么

基于源码的代码覆盖率

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

RUSTFLAGS="-C instrument-coverage" cargo build

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

llvm-tools-preview 组件包含 llvm-profdata 用于处理和合并原始 profile 输出(覆盖区域执行计数);以及用于生成报告的 llvm-covllvm-covllvm-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 feature 的新语法

此版本引入了两个新的变化,以改进对 Cargo feature 的支持以及它们如何与可选依赖交互:命名空间依赖(Namespaced dependencies)和弱依赖 feature(weak dependency features)。

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

[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 隐式定义了一个同名 feature。启用 jpeg-decoder feature 将启用 jpeg-decoder 依赖。
  • "jpeg-decoder/rayon" 语法启用 jpeg-decoder 依赖,并且启用 jpeg-decoder 依赖的 rayon feature。

命名空间 feature 解决了第一个问题。您现在可以在 [features] 表中使用 dep: 前缀来显式引用可选依赖,而无需将其隐式暴露为 feature。这让您在定义对应可选依赖的 feature 时拥有更多控制权,包括将可选依赖隐藏在更具描述性的 feature 名称后面。

弱依赖 feature 解决了第二个问题,即 "optional-dependency/feature-name" 语法总是会启用 optional-dependency。然而,通常您只想在其他某个 feature 启用了可选依赖时,启用该可选依赖上的 feature。从 1.60 开始,您可以添加一个 ?,例如 "package-name?/feature-name",这只会在其他某些东西启用了可选依赖时才启用指定的 feature。

例如,假设我们为库添加了一些序列化支持,并且需要在某些可选依赖中启用相应的 feature。这可以这样做:

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

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

在此示例中,启用 serde feature 将启用 serde 依赖。它还会为 rgb 依赖启用 serde feature,但仅在其他某些东西启用了 rgb 依赖时才行。

增量编译状态

1.60 版本重新启用了增量编译。Rust 团队继续努力修复增量编译中的错误,但目前已知没有导致广泛破坏的问题,因此我们决定重新启用增量编译。此外,编译器团队正在继续制定长期策略以避免将来出现此类问题。该过程尚处于早期阶段,因此目前还没有任何可以分享的进展。

Instant 的单调性保证

在所有平台上,如果可用,Instant 会尝试使用保证单调行为的操作系统 API(所有 tier 1 平台都是这种情况)。实践中,在极少数情况下,此类保证会因硬件、虚拟化或操作系统错误而失效。为了规避这些错误以及不提供单调时钟的平台,Instant::duration_sinceInstant::elapsedInstant::sub 现在会饱和到零。在旧版本 Rust 中,这会导致 panic。可以使用 Instant::checked_duration_since 来检测和处理单调性被违反或 Instant 按错误顺序相减的情况。

这个权宜之计会掩盖意外交换了较早和较晚 Instant 的编程错误。出于这个原因,如果可能且高效,未来 Rust 版本可能会至少在这些情况下重新引入 panic。

在 1.60 之前,单调性保证是通过 std 中的互斥锁或原子操作提供的,这可能会给 Instant::now() 带来很大的性能开销。此外,panic 行为意味着 Rust 软件可能会在部分环境中 panic,这在很大程度上是不可取的,因为该软件的作者可能无法修复或升级其运行的操作系统、硬件或虚拟化系统。此外,在这些环境中引入意外的 panic 会使 Rust 软件的可靠性和可移植性降低,这比向最终用户暴露单调时钟处理中通常不重要的平台错误更令人关注。

稳定的 API

以下方法和 trait 实现现已稳定

其他变化

Rust 1.60.0 版本还有其他变化。请查看 RustCargoClippy 中的变化。

1.60.0 贡献者

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