编译器错误 E0764:常量中使用可变引用
2026/9/11 23:33:22 网站建设 项目流程

编译器错误 E0764:常量中使用可变引用

【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust

导读

本文围绕 Rust 编译器(rustc)错误码E0764(在常量/静态项中使用了可变引用&mut)展开,结合当前仓库中该错误的定义文档、诊断实现与测试用例,完整讲解错误的触发场景、背后的设计动机(防止“全局可变常量”)、修复方案,以及const fn为何可以安全使用&mut的底层原理。读完本文,你将能准确诊断此类编译错误,并掌握在conststaticconst fn之间正确放置&mut引用的边界。

一、错误速览:E0764 是什么

E0764 的官方定义位于 compiler/rustc_error_codes/src/error_codes/E0764.md,其核心描述为:

A mutable reference was used in a constant.(在常量中使用了可变引用。)

也就是说:在conststatic的求值表达式中,如果最终值里包含&mut可变引用,编译器就会报出 E0764。

二、最小复现示例

文档给出的最简错误示例:

fn main() { const OH_NO: &'static mut usize = &mut 1; // error! }

这里把&mut 1(对临时值1的可变借用)赋给常量OH_NO。编译时会得到类似如下的诊断:

error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> src/main.rs:2:34 | 2 | const OH_NO: &'static mut usize = &mut 1; // error! | ^^^^ this mutable borrow refers to such a temporary | = note: temporaries in constants and statics can have their lifetime extended until the end of the program = note: to avoid accidentally creating global mutable state, such temporaries must be immutable

三、为什么会禁止:设计动机

文档明确指出,这一限制的存在是为了防止在常量/静态项的最终值中出现可变引用。原因很直接:

如果你有一个&mut i32类型的常量,就可以通过该引用修改其指向的值,从而让常量实质上变成可变的——即“全局可变状态”。

常量在 Rust 语义中意味着“编译期可确定、不可变、可内联到使用点”,一旦允许&mut泄漏进最终值,任何代码都能借由此引用改写“常量”,破坏这一保证。

值得一提的是,文档也给出了设计取舍的说明:

未来或许存在更细粒度的方案(只要&mut不“泄漏”到最终值就允许使用),但现阶段选择了更保守的策略:一律禁止。

这种保守策略换来的直接收益是:规则简单、可预测,而const fn内部借用检查器足以防止新的可变引用逃逸到返回值中(详见第五节)。

源码中的诊断实现

当前仓库中 E0764 对应MutableBorrowEscaping诊断结构体,位于 compiler/rustc_const_eval/src/diagnostics.rs:

#[derive(Diagnostic)] #[diag("mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed", code = E0764)] #[note( "temporaries in constants and statics can have their lifetime extended until the end of the program" )] #[note("to avoid accidentally creating global mutable state, such temporaries must be immutable")] #[help( "if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`" )] pub(crate) struct MutableBorrowEscaping { #[primary_span] #[label("this mutable borrow refers to such a temporary")] pub span: Span, pub kind: ConstContext, }

可见编译器不仅报错,还会附带两条note与一条help,直接提示修复方向(内嵌可变staticstatic mut),这正是我们下一节要讲的解决方案。

四、如何修复:三条可靠路径

路径 1:改用不可变引用&T

如果语义上只需要只读访问,直接把&mut换成&即可:

const OK: &'static usize = &1; // ok!

路径 2:把“可变”挪进static/static mut

如果确实需要全局可变状态,文档与诊断信息共同给出的建议是使用显式的static mut或具有内部可变性的static

// 显式的 static mut,编译器允许通过它建立 &mut static mut BUFFER: i32 = 42; const fn ptr_to_buffer() -> Option<&'static mut i32> { unsafe { Some(&mut *std::ptr::addr_of_mut!(BUFFER)) } } const MUT_TO_BUFFER: Option<&mut i32> = ptr_to_buffer(); // ok!

该例取自 tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:因为存在显式的static mut声明,可变状态有明确归属,因此允许常量/静态引用它,测试注释明确写道 “Allowed, because there is an explicit static mut.”。同一文件中还有对应的合法示例:

static mut MUT_ARRAY: &mut [u8] = &mut [42]; static MUTEX: std::sync::Mutex<&mut [u8]> = std::sync::Mutex::new(unsafe { &mut *MUT_ARRAY }); // ok!

(见 mut_ref_in_final.rs,“Just statics pointing to mutable statics, nothing fundamentally wrong with this.”)

路径 3:改用具有内部可变性的容器(如Mutex/UnsafeCell

诊断的help提示 “interior mutablestatic”,即通过static Mutex<T>static AtomicU32这类类型把可变性封装在安全接口之后,而非让&mut直接暴露在常量值中。

注意static mut本身在现代 Rust 中被视为不鼓励的用法(依赖static_mut_refs等 lint),示例代码中均使用了unsafe,这是 Rust 当前语义下的必然要求;本文仅作技术说明,不构成对生产代码的建议。

五、const fn中为什么可以用&mut

文档强调了一个看似矛盾、实则自洽的事实:可变引用不能出现在const/static的最终值里,但完全可以出现在const fn的函数体内

const fn foo(x: usize) -> usize { let mut y = 1; let z = &mut y; *z += x; y } fn main() { const FOO: usize = foo(10); // ok! }

原因有两层:

  1. 作用域封闭const fn内部的局部变量(如y)生命周期随函数调用结束而结束,&mut y无法逃逸到函数返回值之外;借用检查器保证了const fn不会返回新建的可变引用
  2. 返回值是具体值:上述foo返回的是usizey的值),&mut只是计算过程中的临时工具,最终值里根本不存在引用,自然不构成 E0764。

补充说明:文档同时提醒“不可以在const/static中调用普通函数”,因为普通函数可能有副作用、无法保证编译期求值;而const fn可在编译期求值,因此能在常量初始化中放心调用。

六、更精细的边界:临时值 vs. 显式static mut

E0764 的判定并非“一切&mut进常量都禁止”,而是针对“生命周期被延长到程序结束的临时值”。这一点在测试中有非常清晰的刻画:

  • 禁止const B: *mut i32 = &mut 4;(对临时值4的可变借用,见 mut_ref_in_final.rs);
  • 允许const B2: Option<&mut i32> = None;(没有实际的可变分配,见同文件 L19);
  • 允许const C: *const i32 = &{ let mut x = 42; x += 3; x };(块先把值 move 出去再取引用,见同文件 L35-L39)。

同一思路在 tests/ui/consts/issue-17718-const-bad-values.rs 也有体现:

const C1: &'static mut [usize] = &mut []; //~ ERROR: mutable borrows of temporaries static mut S: i32 = 3; const C2: &'static mut i32 = unsafe { &mut S }; // ok:指向显式 static mut

另外,staticconst一视同仁,同样受此限制。测试 mut_ref_in_final.rs 里,static RAW_MUT_CAST_Sstatic RAW_MUT_COERCE_Sconst RAW_MUT_CAST_Cconst RAW_MUT_COERCE_C四者全部报出 “mutable borrows of temporaries” 错误——无论&mut被强转为*mut/*const还是藏在结构体字段中,只要指向被延长生命周期的临时值,都会被拦截。

源码侧如何判定

该判定的底层实现位于 compiler/rustc_const_eval/src/check_consts/ops.rs:

/// This op is for `&mut` borrows in the trailing expression of a constant /// which uses the "enclosing scopes rule" to leak its locals into anonymous /// static or const items. pub(crate) struct EscapingMutBorrow;

EscapingMutBorrow实现了NonConstOptrait,其status_in_item直接返回Status::Forbidden(恒禁止),并在build_error中创建MutableBorrowEscaping(即 E0764)诊断。这里的 “enclosing scopes rule” 指的正是:常量的尾表达式会把局部临时值“泄漏”成匿名静态/常量项,使其生命周期延长至程序结束——这正是 E0764 要堵住的洞口。

七、常见疑问速查

场景是否触发 E0764说明
const X: &mut i32 = &mut 1;可变借用泄漏进最终值
static X: &mut i32 = &mut 1;static同样受限
const fn f() { let z = &mut y; ... }借用不逃逸、最终值不含引用
const X: &i32 = &1;不可变引用允许
static mut S: i32 = 1; const X: &mut i32 = unsafe { &mut S };显式static mut提供归属
const X: Option<&mut i32> = None;最终值不含实际可变分配
普通函数调用出现在const初始化中否(但报其他错)常量中不能调用非常量函数

八、小结

E0764 是 Rust 为保证常量语义纯净性而设的“防火墙”:const/static的最终值中不允许出现&mut。遇到该错误时,按以下顺序排查:

  1. 确认是否真的需要可变性——若只需只读,改用&T
  2. 若需要全局可变状态,改用显式static mutMutex/AtomicU32等内部可变类型;
  3. 若只是计算过程中的临时借用,把逻辑封装进const fn,让借用检查器替你兜底。

结合 E0764 定义文档、诊断实现、判定逻辑 以及 约束测试用例,你可以完整追溯该错误的“为什么”与“怎么办”,并把它推广到任何涉及const/static与引用交织的代码审查中。

【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询