Rust 1.85.0 版本发布以及 Rust 2024
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 指南包含了关于每个更改的详细信息,但作为摘要,以下是所有更改:
语言
RPIT 生命周期捕获规则 — 更改了当 use<..> 不存在时,impl Trait 类型默认捕获参数的方式。
if let 临时作用域 — 更改了 if let 表达式中临时变量的作用域。
尾表达式临时作用域 — 更改了块中尾表达式的临时变量作用域。
Match ergonomics 保留 — 禁止某些模式组合以避免混淆,并为未来的改进留出空间。
Unsafe extern 代码块 — extern 代码块现在需要 unsafe 关键字。
Unsafe 属性 — export_name、link_section 和 no_mangle 属性现在必须标记为 unsafe。
unsafe_op_in_unsafe_fn 警告 — unsafe_op_in_unsafe_fn lint 现在默认发出警告,要求在 unsafe 函数中使用显式的 unsafe {} 代码块。
禁止引用 static mut — 现在默认拒绝生成对 static mut 项的引用。
Never 类型回退更改 — 更改了 never 类型 ! 的强制转换方式,并将 never_type_fallback_flowing_into_unsafe lint 级别更改为 "deny"。
宏片段指定符 — macro_rules! 宏中的 expr 宏片段指定符现在也匹配 const 和 _ 表达式。
缺少宏片段指定符 — missing_fragment_specifier lint 现在是一个硬错误,拒绝没有片段指定符类型的宏元变量。
gen 关键字 — 保留 gen 关键字,以期将来添加生成器块。
保留语法 — 保留 #"foo"# 风格的字符串和 ## tokens,以期将来更改受保护字符串字面量的解析方式。
标准库
对 prelude 的更改 — 将 Future 和 IntoFuture 添加到 prelude 中。
为 Box<[T]> 添加 IntoIterator — 更改了迭代器如何与 boxed slice 一起工作。
新增 unsafe 函数 — std::env::set_var、std::env::remove_var 和 std::os::unix::process::CommandExt::before_exec 现在是 unsafe 函数。
Cargo
Cargo:Rust 版本感知解析器 — 更改了默认的依赖解析器行为,使其考虑 rust-version 字段。
Cargo:表和键名一致性 — 移除了一些过时的 Cargo.toml 键。
Cargo:拒绝未使用的继承 default-features — 更改了 default-features = false 如何与继承的工作区依赖项一起工作。
Rustdoc
Rustdoc 合并测试 — Doctests 现在合并到一个可执行文件中,显著提高了性能。
Rustdoc 嵌套 include! 更改 — 更改了嵌套 include! 文件的相对路径行为。
Rustfmt
Rustfmt:样式 Edition — 引入了 “样式 Edition” 的概念,允许您独立于 Rust Edition 控制格式化 Edition。
Rustfmt:格式化修复 — 大量修复了各种情况下的格式化问题。
Rustfmt:原始标识符排序 — 更改了 r#foo 标识符的排序方式。
Rustfmt:版本排序 — 更改了包含整数的标识符的排序方式。
迁移到 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:AsyncFn、AsyncFnMut 和 AsyncFnOnce。
在某些情况下,您已经可以使用常规闭包和异步代码块来近似实现这一点,例如 || async {}。但是,此类内部代码块返回的 future 无法从闭包捕获中借用,但这在使用 async 闭包时可以实现。
let mut vec: Vec
let closure = async || {
vec.push(ready(String::from("")).await);
};
使用返回 Future 的 Fn trait 也一直无法正确表达高阶函数签名,但是您可以使用 AsyncFn trait 来编写它。
use core::future::Future;
async fn f
where
Fut: Future
{ 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
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
| --- ^^^ ^
| |
| 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
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,有关更多详细信息,请参阅当前的参考文档。
元组的 FromIterator 和 Extend
早期版本的 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
BuildHasherDefault::new
ptr::fn_addr_eq
io::ErrorKind::QuotaExceeded
io::ErrorKind::CrossesDevices
{float}::midpoint
Unsigned {integer}::midpoint
NonZeroU*::midpoint
impl std::iter::Extend for tuples with arity 1 through 12
FromIterator<(A, ...)> for tuples with arity 1 through 12
std::task::Waker::noop
这些 API 现在在 const 上下文中是稳定的
mem::size_of_val
mem::align_of_val
Layout::for_value
Layout::align_to
Layout::pad_to_align
Layout::extend
Layout::array
std::mem::swap
std::ptr::swap
NonNull::new
HashMap::with_hasher
HashSet::with_hasher
BuildHasherDefault::new
MaybeUninit::write
其他更改
查看 Rust、Cargo 和 Clippy 中更改的所有内容。
1.85.0 版本的贡献者
许多人共同努力创建了 Rust 1.85.0 版本。没有你们所有人,我们不可能做到这一点。谢谢!