为何Rust不为val3引用的临时变量延长作用域?
unwrap_or(&mut 0)临时值作用域不延长的原因分析 先看问题中的代码:
fn main() { let mut vec = vec![1, 2,3]; let val1 = vec.get(0).unwrap_or(&0); println!("{val1}"); let val2 = match vec.get_mut(0) { Some(v) => v, None => &mut 0, }; println!("{val2}"); let val3 = vec.get_mut(0).unwrap_or(&mut 0); println!("{val3}"); }
编译时val3会触发如下错误:
error[E0716]: temporary value dropped while borrowed --> src/main.rs:13:46 | 13 | let val3 = vec.get_mut(0).unwrap_or(&mut 0); | ^ - temporary value is freed at the end of this statement | | | creates a temporary value which is freed while still in use 14 | println!("{val3}"); | ------ borrow later used here | help: consider using a `let` binding to create a longer lived value | 13 ~ let binding = 0; 14 ~ let val3 = vec.get_mut(0).unwrap_or(&mut binding); | For more information about this error, try `rustc --explain E0716`. error: could not compile `question` (bin "question") due to 1 previous error
三个案例的差异原因
1. val1:不可变引用的unwrap_or正常运行
vec.get(0)返回Option<&i32>,对应的unwrap_or签名是fn unwrap_or(self, default: &i32) -> &i32。由于不可变引用实现了Copy trait,传入&0时,临时值0的引用会被复制一份传入函数,最终返回的引用仍然指向这个临时值。
Rust有一条临时值作用域延长规则:当临时值的引用被直接绑定到一个变量时,临时值的生命周期会延长到该变量的生命周期结束。这里val1绑定了返回的引用,所以临时值0的生命周期被延长到val1失效,因此可以正常打印。
2. val2:match中的可变引用正常运行
match的分支直接将&mut 0返回并绑定给val2,属于直接将临时值的引用绑定到变量的场景,触发了Rust的临时值作用域延长规则。临时值0的生命周期被延长到val2的生命周期结束,所以后续打印不会报错。
3. val3:可变引用的unwrap_or报错
vec.get_mut(0)返回Option<&mut i32>,对应的unwrap_or签名是fn unwrap_or(self, default: &mut i32) -> &mut i32。可变引用没有实现Copy,传入&mut 0时,这个临时引用会被移动到unwrap_or函数内部。
虽然unwrap_or最终会返回这个传入的可变引用,但Rust无法识别返回的引用和原临时值的关联——因为引用已经被移动进函数,返回的引用相当于函数的输出,而非直接绑定临时值到val3的情况。因此临时值0的生命周期不会被延长,在当前语句结束后就会被销毁,而val3还持有它的引用,最终触发“临时值被销毁但仍被借用”的错误。
你的猜测验证
你对差异的核心判断是正确的:
- match场景中,临时值的引用直接赋值给变量,触发作用域延长;
- unwrap_or场景中,可变引用被移动进函数,无法触发临时值作用域延长,而不可变引用因为Copy特性,保留了和临时值的绑定关系,因此可以正常运行。
内容的提问来源于stack exchange,提问作者Ben Marzinski

