宣布 Rust 1.80.0

2024 年 7 月 25 日 · Rust 发布团队

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

如果你之前通过 rustup 安装了 Rust,你可以通过以下命令获取 1.80.0 版本:

$ rustup update stable

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

如果你想通过测试未来版本来帮助我们,可以考虑将本地更新到 beta 通道 (rustup default beta) 或 nightly 通道 (rustup default nightly)。请 报告 你遇到的任何错误!

1.80.0 稳定版中有什么

LazyCellLazyLock

这些“惰性”类型会延迟其数据的初始化,直到首次访问。它们类似于 在 1.70 版本中稳定OnceCellOnceLock 类型,但将初始化函数包含在单元中。这完成了将流行 crate lazy_staticonce_cell 中的功能引入标准库的稳定化工作。

LazyLock 是线程安全的选项,使其适用于 static 值等地方。例如,下面的 spawn 线程和主 scope 都将看到完全相同的 Duration,因为 LAZY_TIME 将由最先访问该 static 的那个初始化一次。与使用 OnceLock::get_or_init() 不同,它们都不必知道如何初始化它。

use std::sync::LazyLock;
use std::time::Instant;

static LAZY_TIME: LazyLock<Instant> = LazyLock::new(Instant::now);

fn main() {
    let start = Instant::now();
    std::thread::scope(|s| {
        s.spawn(|| {
            println!("Thread lazy time is {:?}", LAZY_TIME.duration_since(start));
        });
        println!("Main lazy time is {:?}", LAZY_TIME.duration_since(start));
    });
}

LazyCell 在没有线程同步的情况下执行相同的操作,因此它不实现 Syncstatic 所需),但它仍可用于 thread_local! static(每个线程独立初始化)。这两种类型也可以用于其他数据结构,具体取决于线程安全需求,因此惰性初始化随处可用!

检查 cfg 名称和值

在 1.79 版本中,rustc 稳定了 --check-cfg flag,现在 Cargo 1.80 为它知道的所有 cfg 名称和值启用了这些检查(除了来自 rustc已知名称和值之外)。这包括来自 Cargo.toml 的 feature 名称以及来自构建脚本的新的 cargo::rustc-check-cfg 输出。

意外的 cfg 由默认警告的 unexpected_cfgs lint 报告,该 lint 用于捕获拼写错误或其他配置错误。例如,在一个具有可选 rayon 依赖项的项目中,此代码配置了错误的 feature

fn main() {
    println!("Hello, world!");

    #[cfg(feature = "crayon")]
    rayon::join(
        || println!("Hello, Thing One!"),
        || println!("Hello, Thing Two!"),
    );
}
warning: unexpected `cfg` condition value: `crayon`
 --> src/main.rs:4:11
  |
4 |     #[cfg(feature = "crayon")]
  |           ^^^^^^^^^^--------
  |                     |
  |                     help: there is a expected value with a similar name: `"rayon"`
  |
  = note: expected values for `feature` are: `rayon`
  = help: consider adding `crayon` as a feature in `Cargo.toml`
  = note: see <https://doc.rust-lang.net.cn/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
  = note: `#[warn(unexpected_cfgs)]` on by default

无论实际的 rayon feature 是否启用,都会报告相同的警告。

Cargo.toml manifest 中的 [lints] 表也可用于扩展自定义 cfg 的已知名称和值列表。rustc 会自动提供用于警告中的语法

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(foo, values("bar"))'] }

你可以在一篇先前的博客文章中阅读更多关于此功能的信息,该文章宣布了该功能在 nightly 版本中可用。

模式中的独占范围

Rust 的范围模式现在可以使用独占终点,写为 a..b..b,类似于 RangeRangeTo 表达式类型。例如,以下模式现在可以使用相同的常量作为某个模式的结尾和下一个模式的开头

pub fn size_prefix(n: u32) -> &'static str {
    const K: u32 = 10u32.pow(3);
    const M: u32 = 10u32.pow(6);
    const G: u32 = 10u32.pow(9);
    match n {
        ..K => "",
        K..M => "k",
        M..G => "M",
        G.. => "G",
    }
}

以前,模式中只允许包含(a..=b..=b)或开放(a..)范围,因此像这样的代码需要为 K - 1 这样的包含终点使用单独的常量。

独占范围作为不稳定功能已经实现很久了,但主要顾虑是它们可能增加模式中的混淆和差一错误的可能性。为此,穷尽性检查已得到增强,以更好地检测模式匹配中的间隙,并且新的 lints non_contiguous_range_endpointsoverlapping_range_endpoints 将帮助检测你可能希望将独占模式切换为包含模式的情况,反之亦然。

稳定的 API

这些 API 现在在 const 上下文中稳定。

其他变化

查看 RustCargoClippy 中发生的所有变化。

1.80.0 的贡献者

许多人共同努力创建了 Rust 1.80.0。没有大家,我们不可能做到。感谢!