升级到Rust 2024版本后宏因临时值释放报错,如何修复?
Rust 2024版本下expect宏的临时值生命周期问题
问题背景
原有代码在Rust 2021中可正常运行,但升级到2024版本后出现临时值提前释放的错误。核心原因是Rust 2024收紧了临时值的生命周期规则,宏中创建的临时值会在语句结束时被释放,而持有该临时值引用的Subject结构体仍在使用。
原有代码:
#[macro_export] macro_rules! expect { (&$subject:expr) => { expect!($subject) }; ($subject:expr) => {{ let line = line!(); expect(&$subject).with_line(line) }}; } pub fn expect<S>(subject: &S) -> Subject<S> { Subject { subject } } pub struct Subject<'a, S> { subject: &'a S } impl <'a,S> Subject<'a,S> { pub fn with_line(self, line:u32) -> Self { // do something with line self } } fn main() { let s = expect!(String::new()).subject; let sref = "s"; let s = expect!(&sref).subject; }
错误信息:
error[E0716]: temporary value dropped while borrowed --> src/main.rs:31:19 | 8 | expect(&$subject).with_line(line) | - temporary value is freed at the end of this statement ... 31 | let s = expect!(String::new()).subject; | --------^^^^^^^^^^^^^--------- | | | | | creates a temporary value which is freed while still in use | borrow later used here | = note: consider using a `let` binding to create a longer lived value
解决方案
通过修改宏的逻辑,对非引用参数先进行局部变量绑定以延长临时值生命周期,同时修正引用参数的处理逻辑避免多余的引用嵌套:
#[macro_export] macro_rules! expect { // 处理已为引用的参数:直接传递给expect函数,无需额外取引用 (&$subject:expr) => {{ let line = line!(); expect($subject).with_line(line) }}; // 处理非引用参数:先绑定到局部变量延长生命周期,再传递引用 ($subject:expr) => {{ let line = line!(); let subject = $subject; expect(&subject).with_line(line) }}; } pub fn expect<S>(subject: &S) -> Subject<S> { Subject { subject } } pub struct Subject<'a, S> { subject: &'a S } impl <'a,S> Subject<'a,S> { pub fn with_line(self, line:u32) -> Self { // do something with line self } } fn main() { let s = expect!(String::new()).subject; let sref = "s"; let s = expect!(&sref).subject; }
说明
- 对于非引用参数(如
String::new()):宏会先将临时值绑定到局部变量subject,该变量的生命周期覆盖整个语句块,直到let s = ...赋值完成后才会被释放,彻底避免临时值提前释放的问题。 - 对于引用参数(如
&sref):宏直接传递原引用给expect函数,避免了原逻辑中多余的引用嵌套,保证返回的Subject持有正确的引用类型。
内容的提问来源于stack exchange,提问作者CoronA
相关产品推荐
相关产品推荐

