You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级到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;
}

说明

  1. 对于非引用参数(如String::new()):宏会先将临时值绑定到局部变量subject,该变量的生命周期覆盖整个语句块,直到let s = ...赋值完成后才会被释放,彻底避免临时值提前释放的问题。
  2. 对于引用参数(如&sref):宏直接传递原引用给expect函数,避免了原逻辑中多余的引用嵌套,保证返回的Subject持有正确的引用类型。

内容的提问来源于stack exchange,提问作者CoronA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:57:33