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
相关产品推荐
相关产品推荐

