症状
E0716 附带的完整诊断很精确,前提是把整段读完:错误码指出临时值在借用期间被丢弃,note 说明“临时值在语句结束时释放、借用在此之后仍在使用”。机制是:let 右侧创建的临时对象在分号处销毁,而代码想持有它某部分(字段、元素、切片)的引用越过这个时点——这在构造上就是悬垂指针,编译器以 E0716 拒绝。典型形态是 let s = &make().field 与对函数返回值内部取引用的链式调用。
诊断思路
先读完整错误(含 note)确认临时值的作用域边界;再从错误 span 识别哪个子表达式是临时值——所有修法都是给那个值命名;最后用 cargo check 验证绑定中间值后编译通过。match/if-let 对方法结果取引用、单表达式内联构造容器再取元素引用,是两个高频藏身处。
根因
Rust 在所在语句结束时销毁未命名的临时值。借用这种临时值的组成部分会产生生命周期超过所指对象的引用,编译器以 E0716 拒绝,而不是放行一个悬垂指针。
修复与验证
先命名再借用:let owned = build(); let s = &owned.field;——借用指向有名字、活得久的绑定。返回位置的链式调用改为所有权流动:直接返回 String 等拥有类型,把生命周期决定权交给调用者。值很小、拷贝无关性能时,拥有类型优于扭曲的生命周期;clippy 的 redundant clone 警告会看住相反的极端。验证时 cargo check 通过此前失败的函数,测试套件覆盖该路径,且没有新增 clone 警告。设计规则只有一条:借用必须指向某个命名绑定拥有的东西,绝不指向已排定销毁的表达式结果。
代码示例
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:4:13
|
4 | let s = &format!("{}-{}", a, b).to_uppercase();
| ^--------------------------------------
| |
| temporary value is freed at the end of this statement
| borrow later used here
// from:
let s = &build().field;
// to:
let owned = build();
let s = &owned.field; // borrow of a named, lasting binding
fn label(a: &str, b: &str) -> String {
format!("{}-{}", a, b).to_uppercase() // owned: caller decides lifetime
}