Rust 1.60.0 发布公告

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

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

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

$ rustup update stable

如果您还没有安装 rustup,您可以从我们网站的相应页面获取 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 features 的新语法

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

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

[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 名称后面。

弱依赖项 features 解决了第二个问题,即 "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 将尝试使用保证单调行为的 OS API(所有 tier 1 平台都是这种情况)。实际上,在极少数情况下,此类保证会被硬件、虚拟化或操作系统错误破坏。为了解决这些错误和不提供单调时钟的平台,Instant::duration_sinceInstant::elapsedInstant::sub 现在会饱和到零。在较旧的 Rust 版本中,这会导致 panic。可以使用 Instant::checked_duration_since 来检测和处理违反单调性的情况,或者 Instant 以错误的顺序减去的情况。

此解决方法会掩盖意外交换较早和较晚的时间点的编程错误。因此,如果可能且效率高,则未来的 Rust 版本可能会至少在这些情况下重新引入 panic。

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

稳定的 API

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

其他更改

Rust 1.60.0 版本中还有其他更改。查看 RustCargoClippy 中更改的内容。

1.60.0 的贡献者

很多人共同努力创建了 Rust 1.60.0。没有你们大家,我们不可能做到这一点。谢谢!