Rust 1.85.0 版本发布以及 Rust 2024

2025 年 2 月 20 日 · Rust 发布团队

Rust 团队很高兴地宣布 Rust 的新版本 1.85.0 发布。此版本也同时稳定了 2024 Edition。Rust 是一种编程语言,旨在赋能每个人构建可靠且高效的软件。

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

$ rustup update stable

如果您尚未安装,您可以从我们网站上的相应页面获取 rustup,并查看1.85.0 版本的详细发布说明

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

1.85.0 稳定版的新特性

Rust 2024

我们激动地宣布 Rust 2024 Edition 现已稳定!Edition 是一种选择性加入机制,用于引入可能存在向后兼容性风险的更改。有关如何实现此目的的详细信息,以及关于如何迁移的详细说明,请参阅edition 指南

这是我们发布过的最大的 Edition。 edition 指南包含了关于每个更改的详细信息,但作为摘要,以下是所有更改:

迁移到 2024

该指南包括所有新功能的迁移说明,以及将现有项目过渡到新 edition 的通用说明。在许多情况下,cargo fix 可以自动完成必要的更改。您甚至可能发现您的代码根本不需要进行任何 2024 的更改!

请注意,通过 cargo fix 进行的自动修复非常保守,以避免更改您代码的语义。在许多情况下,您可能希望保持代码不变并使用 Rust 2024 的新语义;例如,继续使用 expr 宏匹配器,并忽略条件语句的转换,因为您想要新的 2024 drop order 语义。cargo fix 的结果不应被视为建议,而仅仅是一种保留行为的保守转换。

许多人共同努力创建了这个 edition。我们要感谢所有人的辛勤工作!

async 闭包

Rust 现在支持异步闭包,例如 async || {},它在被调用时返回 futures。这就像一个 async fn,它也可以从本地环境捕获值,就像常规闭包和函数之间的区别一样。这也附带了标准库 prelude 中的 3 个类似的 trait:AsyncFnAsyncFnMutAsyncFnOnce

在某些情况下,您已经可以使用常规闭包和异步代码块来近似实现这一点,例如 || async {}。但是,此类内部代码块返回的 future 无法从闭包捕获中借用,但这在使用 async 闭包时可以实现。

let mut vec: Vec<String> = vec![];

let closure = async || {
    vec.push(ready(String::from("")).await);
};

使用返回 FutureFn trait 也一直无法正确表达高阶函数签名,但是您可以使用 AsyncFn trait 来编写它。

use core::future::Future;
async fn f<Fut>(_: impl for<'a> Fn(&'a u8) -> Fut)
where
    Fut: Future<Output = ()>,
{ todo!() }

async fn f2(_: impl for<'a> AsyncFn(&'a u8))
{ todo!() }

async fn main() {
    async fn g(_: &u8) { todo!() }
    f(g).await;
    //~^ ERROR mismatched types
    //~| ERROR one type is more general than the other

    f2(g).await; // ok!
}

因此,async 闭包为这两个问题提供了第一流的解决方案!有关更多详细信息,请参阅 RFC 3668稳定化报告

从诊断信息中隐藏 trait 实现

新的 #[diagnostic::do_not_recommend] 属性是给编译器的提示,指示不要将带注释的 trait 实现显示为诊断消息的一部分。对于库作者来说,这是一种防止编译器提出可能无益或误导性建议的方法。例如:

pub trait Foo {}
pub trait Bar {}

impl<T: Foo> Bar for T {}

struct MyType;

fn main() {
    let _object: &dyn Bar = &MyType;
}
error[E0277]: the trait bound `MyType: Bar` is not satisfied
 --> src/main.rs:9:29
  |
9 |     let _object: &dyn Bar = &MyType;
  |                             ^^^^ the trait `Foo` is not implemented for `MyType`
  |
note: required for `MyType` to implement `Bar`
 --> src/main.rs:4:14
  |
4 | impl<T: Foo> Bar for T {}
  |         ---  ^^^     ^
  |         |
  |         unsatisfied trait bound introduced here
  = note: required for the cast from `&MyType` to `&dyn Bar`

对于某些 API,您实现 Foo,并通过 blanket 实现间接获得 Bar 可能很有意义。对于另一些 API,可能期望大多数用户直接实现 Bar,因此 Foo 建议是一个虚假的提示。在这种情况下,添加诊断提示将更改错误消息,如下所示:

#[diagnostic::do_not_recommend]
impl<T: Foo> Bar for T {}
error[E0277]: the trait bound `MyType: Bar` is not satisfied
  --> src/main.rs:10:29
   |
10 |     let _object: &dyn Bar = &MyType;
   |                             ^^^^ the trait `Bar` is not implemented for `MyType`
   |
   = note: required for the cast from `&MyType` to `&dyn Bar`

有关原始动机,请参阅 RFC 2397,有关更多详细信息,请参阅当前的参考文档

元组的 FromIteratorExtend

早期版本的 Rust 为 (T, U) 元组对的迭代器实现了便捷 trait,使其行为类似于 Iterator::unzip,在 1.56 版本中添加了 Extend,在 1.79 版本中添加了 FromIterator。现在,这些 trait 已扩展到更多的元组长度,从单例 (T,) 一直到 12 个项目长,(T1, T2, .., T11, T12)。例如,您现在可以使用 collect() 一次性分散到多个集合中:

use std::collections::{LinkedList, VecDeque};
fn main() {
    let (squares, cubes, tesseracts): (Vec<_>, VecDeque<_>, LinkedList<_>) =
        (0i32..10).map(|i| (i * i, i.pow(3), i.pow(4))).collect();
    println!("{squares:?}");
    println!("{cubes:?}");
    println!("{tesseracts:?}");
}
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
[0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561]

std::env::home_dir() 的更新

std::env::home_dir() 已被弃用多年,因为它在某些 Windows 配置中,如果设置了 HOME 环境变量(这不是 Windows 上的标准配置),可能会给出令人惊讶的结果。考虑到与依赖于此非标准配置的代码的兼容性,我们之前避免更改其行为。鉴于此函数已被弃用如此之久,我们现在正在更新其行为以修复错误,随后的版本将删除此函数的弃用警告。

稳定的 API

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

其他更改

查看 RustCargoClippy 中更改的所有内容。

1.85.0 版本的贡献者

许多人共同努力创建了 Rust 1.85.0 版本。没有你们所有人,我们不可能做到这一点。谢谢!