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,以期将来更改受保护字符串字面量的解析方式。
- RPIT 生命周期捕获规则 — 更改了当
- 标准库
- 对 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 函数。
- 对 prelude 的更改 — 将
- Cargo
- Cargo:Rust 版本感知解析器 — 更改了默认的依赖解析器行为,使其考虑
rust-version
字段。 - Cargo:表和键名一致性 — 移除了一些过时的
Cargo.toml
键。 - Cargo:拒绝未使用的继承 default-features — 更改了
default-features = false
如何与继承的工作区依赖项一起工作。
- Cargo:Rust 版本感知解析器 — 更改了默认的依赖解析器行为,使其考虑
- 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<String> = vec![];
let closure = async || {
vec.push(ready(String::from("")).await);
};
使用返回 Future
的 Fn
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,有关更多详细信息,请参阅当前的参考文档。
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 12std::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
<float>::recip
<float>::to_degrees
<float>::to_radians
<float>::max
<float>::min
<float>::clamp
<float>::abs
<float>::signum
<float>::copysign
MaybeUninit::write
其他更改
查看 Rust、Cargo 和 Clippy 中更改的所有内容。
1.85.0 版本的贡献者
许多人共同努力创建了 Rust 1.85.0 版本。没有你们所有人,我们不可能做到这一点。谢谢!