如何使用 #![feature(const_mut_refs)]?
解读
在国内 Rust 岗位面试中,const_mut_refs 属于“Nightly-only 特性”,面试官通常想确认三件事:
- 候选人是否清楚“稳定版(stable)不能用”这一红线;
- 是否理解 const 上下文里为何默认禁止
&mut; - 能否给出 最小可编译示例 并解释其 UB 边界。
回答时务必先强调“仅用于实验或内部工具链,上线代码必须走 RFC 稳定流程”,否则会被直接判为“工程素养不足”。
知识点
- const fn 的求值发生在编译期,内存模型是“编译时虚拟栈”,mutable borrow 一旦逃逸到运行期会造成双重借用,属于 UB。
#![feature(const_mut_refs)]打开后,const fn 内部可对指向编译时常量的 &mut T 进行写操作,但写结果不会回写到最终二进制,仅影响编译期求值。- 使用限制:
- 必须 nightly toolchain:
rustup default nightly - 必须 crate 级别打开:
#![feature(const_mut_refs)] - 不允许把
&mut返回给调用者,否则编译器会报 “mutable reference in const fn”
- 必须 nightly toolchain:
- 与 const_evaluatable_checked、const_fn_trait_bound 等特性交叉时,需关注 feature 依赖顺序;CI 中必须 pin nightly 版本,防止语法突变。
- 国内银行、券商、车联网等安全审计场景,源码扫描工具(如 Rust-SEC、自研 SIG)会直接拦截任何 #![feature(...)];面试中应补充“如要上线,需等待 trait 稳定或改用 macro/typenum 等零成本替代方案”。
答案
-
环境准备
rustup install nightly rustup default nightly rustup component add rust-src -
新建实验 crate
cargo new --lib const_mut_demo cd const_mut_demo -
在 src/lib.rs 顶部整 crate 声明特性
#![feature(const_mut_refs)] pub const fn add_one(x: &mut u32) { *x += 1; } // 编译期求值,运行期不可见 pub const VAL: u32 = { let mut a = 10; add_one(&mut a); a }; #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { // 运行期拿到的是编译期计算后的常量 assert_eq!(VAL, 11); } } -
编译验证
cargo +nightly test --release若误用 stable,会收到 error[E0554]:
#![feature]may not be used on the stable release channel;
若试图 返回 &mut 给调用者,会收到 error[E0658]: mutable references in const fn are unstable。 -
上线替代方案
- 用 const-generic + trait 实现编译期递归,避免
&mut; - 用 macro_rules! 生成常量数组;
- 等待 const_mut_refs 进入 beta/stable 并经过 RFC 评审后再迁移。
- 用 const-generic + trait 实现编译期递归,避免
拓展思考
- 如果面试官追问“为何 Rust 不让 const fn 返回 &mut T”,可从 MIRI 的 Stacked Borrows 模型角度回答:编译期内存地址在二进制加载时不再存在,返回的引用会指向无效地址,造成悬垂指针。
- 对比 C++20 consteval:C++ 允许 constexpr mutable 但禁止 mutable 逃逸到运行期;Rust 的设计更严格,直接语法层面封杀,体现“编译通过即正确”的保守哲学。
- 国内大型 Rust 项目(如某云原生网络代理)的实践经验:把 const 计算拆成独立 crate,用 build.rs + nightly 在编译机生成常量表,最终产物用 stable 链接,既利用 nightly 特性,又满足生产审计要求。面试中若能提到这一“双工具链隔离”套路,可大幅加分。