Rust 团队很高兴地宣布 Rust 新版本 1.65.0 发布。Rust 是一种编程语言,旨在帮助每个人构建可靠且高效的软件。
在深入了解 Rust 新版本的细节之前,我们想提请大家注意玛莎·阿米尼 (Mahsa Amini) 的悲惨去世,以及伊朗宗教道德警察对许多其他人的杀害和暴力镇压。有关更多详细信息,请参阅 https://en.wikipedia.org/wiki/Mahsa_Amini_protests。我们与伊朗人民站在一起,支持他们为争取人权而奋斗。
如果您之前通过 rustup 安装了 Rust 版本,则可以使用以下命令获取 1.65.0 版本:
$ rustup update stable
如果您尚未安装,您可以从我们网站上的相应页面获取 rustup
,并查看 GitHub 上 1.65.0 版本的详细发行说明。
如果您想通过测试未来的版本来帮助我们,您可以考虑在本地更新以使用 beta 频道 (rustup default beta
) 或 nightly 频道 (rustup default nightly
)。请报告您可能遇到的任何错误!
1.65.0 稳定版的新特性
泛型关联类型 (GATs)
现在可以在关联类型上定义生命周期、类型和常量泛型,如下所示:
trait Foo {
type Bar<'x>;
}
很难用几句话来概括它们的用途,所以这里有一些示例 trait,以便您了解它们的功能:
/// An `Iterator`-like trait that can borrow from `Self`
trait LendingIterator {
type Item<'a> where Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
/// Can be implemented over smart pointers, like `Rc` or `Arc`,
/// in order to allow being generic over the pointer type
trait PointerFamily {
type Pointer<T>: Deref<Target = T>;
fn new<T>(value: T) -> Self::Pointer<T>;
}
/// Allows borrowing an array of items. Useful for
/// `NdArray`-like types that don't necessarily store
/// data contiguously.
trait BorrowArray<T> {
type Array<'x, const N: usize> where Self: 'x;
fn borrow_array<'a, const N: usize>(&'a self) -> Self::Array<'a, N>;
}
如您所见,GATs 非常通用,并且能够实现许多当前无法编写的模式。有关更多信息,请查看去年发布的关于 推动稳定化 的帖子或上周发布的 稳定化公告帖子。前者更深入地探讨了上面的一些示例,而后者则讨论了此稳定化的一些已知限制。
更深入的阅读可以在 nightly 参考 或 原始 RFC(最初在 6.5 年前提出!)的关联类型部分找到。
let
-else
语句
这引入了一种新的 let
语句类型,它具有可反驳的模式和发散的 else
代码块,当该模式不匹配时执行。
let PATTERN: TYPE = EXPRESSION else {
DIVERGING_CODE;
};
普通的 let
语句只能使用不可反驳的模式,静态已知始终匹配。该模式通常只是一个变量绑定,但也可能解包复合类型,如结构体、元组和数组。但是,这对于条件匹配(如提取枚举的变体)是不可用的——直到现在!使用 let
-else
,可反驳的模式可以像普通的 let
一样匹配并在周围作用域中绑定变量,否则当模式不匹配时发散(例如 break
、return
、panic!
)。
fn get_count_item(s: &str) -> (u64, &str) {
let mut it = s.split(' ');
let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
panic!("Can't segment count item pair: '{s}'");
};
let Ok(count) = u64::from_str(count_str) else {
panic!("Can't parse integer: '{count_str}'");
};
(count, item)
}
assert_eq!(get_count_item("3 chairs"), (3, "chairs"));
名称绑定的作用域是使其与 match
或 if let
-else
表达式不同的主要因素。您以前可以使用不幸的重复位和外部 let
来近似这些模式
let (count_str, item) = match (it.next(), it.next()) {
(Some(count_str), Some(item)) => (count_str, item),
_ => panic!("Can't segment count item pair: '{s}'"),
};
let count = if let Ok(count) = u64::from_str(count_str) {
count
} else {
panic!("Can't parse integer: '{count_str}'");
};
break
从带标签的代码块中 现在,普通的块表达式可以标记为 break
目标,从而提前终止该块。这听起来有点像 goto
语句,但它不是任意跳转,只是从块内跳转到块的末尾。这在 loop
块中已经可以实现,您可能见过人们编写始终只执行一次的循环,只是为了获得带标签的 break
。
现在,有一个专门用于此目的的语言特性!带标签的 break
也可能包含表达式值,就像循环一样,让多语句块具有提前“返回”值。
let result = 'block: {
do_thing();
if condition_not_met() {
break 'block 1;
}
do_next_thing();
if condition_not_met() {
break 'block 2;
}
do_last_thing();
3
};
拆分 Linux debuginfo
早在 Rust 1.51 中,编译器团队就添加了对 macOS 上 拆分调试信息 的支持,现在此选项在 Linux 上也稳定可用。
-Csplit-debuginfo=unpacked
会将 debuginfo 拆分到多个.dwo
DWARF 对象文件中。-Csplit-debuginfo=packed
将生成一个单独的.dwp
DWARF 包,其中包含与输出二进制文件一起打包的所有 debuginfo。-Csplit-debuginfo=off
仍然是默认行为,它将 DWARF 数据包含在对象和最终二进制文件的.debug_*
ELF 部分中。
拆分 DWARF 使链接器避免处理 debuginfo(因为它不再位于正在链接的对象文件中),这可以加快链接时间!
其他目标现在也接受 -Csplit-debuginfo
作为具有其平台特定默认值的稳定选项,但指定其他值仍然不稳定。
稳定的 API
以下方法和 trait 实现现在已稳定:
std::backtrace::Backtrace
Bound::as_ref
std::io::read_to_string
<*const T>::cast_mut
<*mut T>::cast_const
特别值得注意的是,Backtrace
API 允许随时捕获堆栈回溯,使用通常用于 panic 回溯的相同平台特定实现。这可能有助于为错误类型添加运行时上下文,例如。
这些 API 现在可以在常量上下文中使用:
兼容性说明
- 作为 RLS 弃用 的最后一步,此版本已将 RLS 替换为一个小型 LSP 服务器,该服务器显示弃用警告,建议用户迁移到
rust-analyzer
。
其他更改
Rust 1.65 版本中还有其他更改,包括:
- MIR 内联现在已为优化编译启用。这为实际 crate 提供了 3-10% 的编译时间改进。
- 在调度构建时,Cargo 现在对待处理作业的队列进行排序以提高性能。
查看 Rust、Cargo 和 Clippy 中更改的所有内容。
1.65.0 版本贡献者
许多人共同创建了 Rust 1.65.0。没有你们所有人,我们不可能做到。谢谢!