
Rust 1.100.0 发布,never 类型历经十年正式稳定
来源标题:Announcing Rust 1.100.0
Rust 团队发布 1.100.0 版本,never 类型(代码中写作 !)在经历 10 年和 5 次失败的稳定化尝试后终于稳定,同时完成了该项目的既定目标。never 类型表示发散计算,即永不返回值的计算,其后代码不可达。已安装 rustup 的用户可通过 rustup update stable 升级。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
Rust 团队很高兴地宣布 Rust 新版本 1.100.0。Rust 是一门 empowering everyone to build reliable and efficient software 的编程语言。
如果你之前通过 rustup 安装过 Rust,可以用以下命令获取 1.100.0:
$ rustup update stable
如果你还没有安装,可以从我们网站相应页面获取 rustup,并查看 1.100.0 的详细发布说明。
如果你想通过测试未来版本来帮助我们,可以考虑在本地更新到 beta 通道(rustup default beta)或 nightly 通道(rustup default nightly)。请报告你遇到的任何 bug!
历经 10 年和 5 次失败的稳定化尝试,never 类型终于稳定了!这也完成了这项工作对应的项目目标。
never 类型在代码中写作 !,是规范的空类型(uninhabited type)。它表示发散计算(diverging computation)的类型——这类计算永远不会产生任何值——其后的任何代码都不可达。终止控制流的表达式,例如 return、break 和 std::process::exit,其类型也是 !。
由于 never 类型的值不可能存在,Rust 允许 never-to-any 强制转换,即把 ! 转换为任意其他类型(这正是它区别于其他空类型的地方)。例如,可以用它让 match 或 if 的某个分支不返回值:
fn mrrrow(option: Option<u32>) {
let value = match option {
// x has type u32
Some(x) => x,
// return has type !, which is then coerced to u32,
// allowing the match to pass type checking.
None => return,
};
// ...
虽然 never 类型此前已经可以这样使用和观察到,甚至可以在函数返回类型中命名(-> !),但本次发布允许在任何位置命名 never 类型:
fn infallible_unwrap<T>(res: Result<T, !>) -> T {
// ^^ writing Result<_, !> was not allowed before
let Ok(v) = res;
v
此外,本次发布将 Infallible 改为 never 类型的别名。这使得所有使用 Infallible 的旧 API 都能与 ! 兼容。这是自 Infallible 引入以来就有的计划,也是 never 类型稳定化如此困难的原因之一(waffle 曾就此稳定化过程中的一些困难做过演讲)。
遗憾的是,为了允许修改 Infallible,我们不得不引入一个破坏性变更。本次发布将 2024 之前版本(即 2015、2018 和 2021)中的“never 类型回退”(never type fallback)从 () 改为 !,与 2024 edition 中已经完成的改动类似。这在很大程度上不会被察觉,但在极少数情况下可能影响代码(例如忽略一个返回泛型参数的函数的结果时)。注意,这一变更也可能让编译器把更多代码判定为不可达。
我们尽量将这一破坏性变更的影响降到最低:提前提供了未来兼容性警告,并为因此损坏的公开 crate 发布了修复。如果某个依赖因 never 类型相关问题而失败,请考虑更新它,因为可能已经发布了针对它的修复。
本次发布稳定了 allocator_api 的核心部分,使库作者能够定义可与某些标准库类型(目前是 Vec 和 Box)配合使用的自定义分配器。这些功能通过新稳定化的 Allocator trait 启用。
这是 Allocators 1.0 项目目标的基础。还有很多工作要做,包括扩展可与自定义分配器配合使用的 API 面,以及让它们稳定地用于更多集合和指针类型;不过,既然核心 trait 和设计已经就绪,预计很快会有更多内容稳定下来!
Rust 中的 Drop trait 使得在变量离开作用域时运行代码成为可能,无论我们是 return、? 还是 panic。Drop 是类型的一部分,这意味着在 Rust 中你永远不必关闭 socket。
然而,当你只想在函数退出时无条件运行一些代码时,实现 Drop 可能会觉得有些不便。这就是我们引入 core::mem::DropGuard 的原因:一个新的辅助类型,在被 drop 时运行一个闭包。
DropGuard 接受两个参数:一个变量和一个闭包。它实现了 Deref 和 DerefMut,因此你可以照常继续操作该变量。但当它被 drop 时,会运行闭包并消费该变量。
DropGuard 还实现了一个 dismiss 方法,可以从 guard 中取回变量而不运行析构函数。这使得快速实现带回滚的全有或全无事务式 API 成为可能。下面是一个示例,实现一个解析器,使用 guard 在失败时回滚修改:
use std::mem::DropGuard;
use std::num::ParseIntError;
/// Attempt to parse all strings and push them into nums.
/// If parsing any of them fails, nums remains unchanged.
fn parse_all(nums: &mut Vec<u32>, strings: &[&str]) -> Result<(), ParseIntError> {
let len = nums.len();
let mut nums = DropGuard::new(nums, move |nums| {
nums.truncate(len); // ← 1. Reset the vec on failure
});
for s in strings {
nums.push(s.parse()?); // ← 2. If ? returns an error, roll back
DropGuard::dismiss(nums); // ← 3. Parsing successful, dismiss the guard
Ok(())
召唤零大小类型
由于 Rust 的不安全代码指南仍在制定中,有一点变得很清楚:明确以不安全方式创建零大小类型(zero-sized type)究竟意味着什么,以及我们应该推荐人们如何去做,会非常有用。
这个问题在 Rust 1.100 中由一个函数回答:std::mem::conjure_zst。
不必再使用 transmute ()、MaybeUninit::uninit().assume_init() 或各种其他咒语,这是当你确知这样做安全时,创建零大小类型值的专用方式。如果一个有值类型(inhabited type)没有大小,我们确切知道它必须是哪个值:什么都没有。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。