发布 Rust 1.85.0 和 Rust 2024

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

Rust 团队很高兴发布 Rust 的新版本 1.85.0。此版本同时稳定了 2024 版。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 版现在已经稳定!版本是一种选择性加入的机制,用于引入可能带来向后兼容风险的更改。有关如何实现此目的的详细信息以及迁移说明,请参阅版本指南

这是我们发布的最大的版本。 版本指南包含每个更改的详细信息,但作为总结,以下是所有更改

迁移到 2024 版

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

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

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

async 闭包

Rust 现在支持异步闭包,例如 async || {},它们在被调用时返回 future。这就像一个 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。这些现在已扩展到更多元组长度,从单元素 (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。没有大家的贡献,我们无法完成它。感谢!