返回资讯中心
外部精选
软件工程
#开发者实时流

Rust 编译器稳定版依赖 83 个 nightly 功能构建

来源标题:What Stable Rust Stands On

Rust 编译器在稳定版发布时仍启用了 83 个不同的 nightly 功能,通过设置 RUSTC_BOOTSTRAP=1 绕过 beta 通道的限制。这些功能并非编译器运行所必需,约 90% 可以移除,但保留它们能让 rustc 代码更简洁易读。该机制仅用于构建编译器自身。

Hacker News 最新r4um2026/11/2 · 3 天前26 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

先说一个有意思的数字:83。在我说出它是什么意思之前,你可以先猜一猜。

这是我在查看某个 commit 时,编译器里启用的不同 nightly feature 的数量。 (我统计了 commit f45772e 中编译器每个 crate 的 lib.rs 里 feature attr 内每一个不同的名字。)

我得说明一下,这些 feature 并不是编译器运行所必需的。我很确定,去掉其中大约 90% 的 feature,编译器也能以同样的方式工作。关键在于,它们让代码更简单,读写起来也更舒服。

而且我指的不是那种只有 rustc 内部才说得通的奇奇怪怪的东西(好吧,那种也有,但今天不谈)。其中很多只是普通且非常有用的 feature,你现在(在 nightly 上)就能好好利用它们!

等等,一个 stable 编译器怎么会用到 nightly feature?rustc 是用 Rust 写的,所以要构建它,你得先有另一个 Rust 编译器。构建过程会下载最新的 beta 版本,称为 stage0,并用它来构建新的编译器。

Beta 通常禁止使用任何 unstable feature,所以构建过程会设置一个特殊变量 RUSTC_BOOTSTRAP 为 1,从而允许使用 nightly feature。这个变量只用于构建编译器本身(更多内容见 rustc-dev-guide),所以请不要在你自己的项目里设置它:它会关闭稳定性保证,你的代码可能在任何更新后出问题。

下面是按启用它们的编译器 crate 数量排名的前 5 名: 第 1 名和第 4 名今天会详细讲,其余的只能等另一篇文章了 :p

我首先挑这个,是因为编译器里有 21 个 crate 启用了它,数量最多,你很快就会明白为什么 :D

这个 feature 解决了一个你很可能都遇到过的实际痛点。比如你在写一个小 CLI,想对它的参数做 match:

#![feature(deref_patterns)] fn run(args: Vec<String>) -> String { match &args { ["help"] => "usage: app <command>".to_string(), ["open", file] => format!("opening {file}"), ["rm", files @ ..] => format!("removing {} files", files.len()), _ => "unknown command".to_string(), 警告 这只是为了展示这个 feature,并不是你在写真实 CLI 时该用的写法!

看起来这应该直接就能用,对吧?在 stable 上它不行,而且会绊你两次。首先,这个模式是在对 Vec 做匹配,但切片模式在这里要求的是 slice 或数组:

error[E0529]: expected an array or slice, found Vec<String> --> src/main.rs:3:9 | 3 | ["help"] => "usage: app <command>".to_string(), | ^^^^^^^^ pattern cannot match with input type Vec<String> | help: consider slicing here | 2 | match &args[..] { | ++++

现在切片模式匹配的是 slice,但 "help" 这个模式仍然无法匹配 String 元素,因为 Rust 不会自动解引用 String 把它当作 &str 来匹配:

error[E0308]: mismatched types --> src/main.rs:3:10 | 2 | match &args[..] { | --------- this expression has type &[String] 3 | ["help"] => "usage: app <command>".to_string(), | ^^^^^^ expected String, found &str

所以在 stable 上,你最终会为了这个专门再建一个 vector:

fn run(args: Vec<String>) -> String { let args: Vec<&str> = args.iter().map(String::as_str).collect(); match args.as_slice() { ["help"] => "usage: app <command>".to_string(), // ...

有了 deref pattern,编译器会替你穿透 Vec 和 String,第一个版本直接就能用。

编译器面临的问题是一样的,只是用 Box 而不是 String。rustc 的数据结构里塞满了 box,主要是为了让 enum 保持较小。比如,MIR 中的每一条赋值都存为 Assign(Box<(Place, Rvalue)>)。

有了 deref pattern,寻找“对引用的赋值”的代码可以一次性匹配,直接穿透 box:

// 大致意思是:这行代码看起来像 x = &y 吗? // 如果是,把 lifetime、可变性和 y 本身给我 let StatementKind::Assign((_, Rvalue::Ref(region, borrow_kind, place))) = &mut statement.kind else { bug!() };

没有这个 feature 就得两步:先把 box 取出来,再解引用它并匹配里面的内容。

let StatementKind::Assign(assign) = &mut statement.kind else { bug!() }; let (_, Rvalue::Ref(region, borrow_kind, place)) = &mut **assign else { bug!() };

box 模式已移除

编译器以前用另一个 feature 做这件事,即 box_patterns,它需要一个显式关键字:Assign(box (lhs, ref rhs))。box_patterns 从来就没打算被稳定,因为 deref_patterns 做了同样的事而且更多。但它也不能简单地删掉,因为编译器自己到处都在用它。所以在一次 MCP 之后,2026 年 5 月的一系列 PR(从 #156193 开始)逐个 crate 地过了一遍编译器并替换掉了它们。

一旦没有任何东西再依赖它,#156749 就把 box_patterns 从编译器里彻底移除了。它在 2026 年 8 月落地,我是那个 PR 的指定 reviewer,@fmease 也帮了忙 :3

现在这个 feature 留下的唯一说明写着“已被 deref_patterns 取代”。

它适用于 Box、String、Vec、Rc、Arc、Cow 以及另外几个,但不是对每个实现了 Deref 的类型都适用。要穿透指针做匹配,编译器必须假设解引用它每次都会得到相同的东西,否则检查一个 match 覆盖所有情况就会是不健全的。但 Deref 只是一个包含普通代码的 trait,没有任何东西能阻止有人写一个每次调用都返回不同东西的实现。所以它只适用于实现了 unsafe 标记 trait DerefPure 的类型。标准库为自己的指针类型实现了它,但你自己的类型不会自动获得:

#![feature(deref_patterns)] use std::ops::Deref; struct Name(String); impl Deref for Name { type Target = String; fn deref(&self) -> &String { &self.0 } fn main() { match Name("ferris".into()) { "ferris" => println!("hi!"), _ => {}

error[E0277]: the trait bound Name: DerefPure is not satisfied --> src/main.rs:13:9 | 13 | "ferris" => println!("hi!"), | ^^^^^^^^ unsatisfied trait bound | help: the nightly-only, unstable trait DerefPure is not implemented for Name

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →