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

Rust中format_args!赋值变量后出现临时值提前释放编译错误的疑问

format_args!赋值变量后编译失败的原因解析

现象

Rust版本:1.69.0

这段代码可以正常运行:

fn main() {
    println!("{}", format_args!("hello {}", "world"));
}

但将format_args!的结果赋值给变量后,会触发借用检查错误:

fn main() {
    let args = format_args!("hello {}", "world");
    println!("{}", args);
}

错误信息:

error[E0716]: temporary value dropped while borrowed
 --> src/main.rs:2:16
  |
2 |     let args = format_args!("hello {}", "world");
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
  |                |
  |                creates a temporary value which is freed while still in use
3 |     println!("{}", args);
  |                    ---- borrow later used here
  |
  = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider using a `let` binding to create a longer lived value
  |
2 ~     let binding = format_args!("hello {}", "world");
3 ~     let args = binding;
  |

核心原因

1. format_args!的内部实现细节

format_args!宏返回的fmt::Arguments<'a>结构体并非完全持有所有数据——它会引用宏内部生成的临时参数数组。这个数组用来存储格式化所需的参数引用,但其生命周期仅限于format_args!调用的当前语句。

2. 临时值生命周期的差异

  • 直接传参给println!:Rust的临时值提升规则会将这个临时参数数组的生命周期延长到整个println!调用结束,此时Arguments的引用始终有效,所以代码可以正常运行。
  • 赋值给变量:在let args = format_args!(...)语句执行完毕后,临时参数数组会立即被销毁,但args仍持有对它的引用。后续println!使用args时,就会触发悬垂引用错误。

3. 无效的编译器建议

编译器给出的新增binding变量的建议完全没用——binding和args的生命周期完全一致,临时参数数组依然会在语句结束时销毁,无法解决根本问题。

解决办法

根据你的需求,有三种常用方案:

方案一:转为String(简单通用)

如果可以接受堆内存分配,直接用format!替代format_args!,将格式化结果转为拥有独立生命周期的String:

fn main() {
    let args = format!("hello {}", "world");
    println!("{}", args);
}

方案二:手动构造Arguments(无堆分配)

如果需要无堆分配的复用,可以直接调用fmt::Arguments::new_v1手动构造,确保所有引用的生命周期足够长:

use std::fmt;

fn main() {
    let fmt_str = "hello {}";
    // 手动构造参数数组,确保其生命周期与变量绑定
    let args_array = &[&"world" as &dyn fmt::Display];
    let args = fmt::Arguments::new_v1(&[fmt_str], args_array);
    println!("{}", args);
}

方案三:使用第三方库(编译时格式化)

如果需要编译时完成格式化且无堆分配,可以使用const_format crate:

use const_format::formatcp;

fn main() {
    let args = formatcp!("hello {}", "world");
    println!("{}", args);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:45:02