为什么 Rust 不扩展以下代码中 val3 引用的临时值的范围:
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}");
}
编译出现以下错误
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
查看 val1 的代码,这将适用于使用 unwrap_or() 的不可变引用。查看 val2 的代码,这将适用于使用 match 表达式的可变引用。但显然它不适用于使用 unwrap_or() 进行可变引用的 val3。有谁知道差异的原因吗?
如果我不得不大胆猜测,我会说 match 表达式可以工作,因为对临时值的可变引用会立即分配给 let 语句中的变量。当使用 unwrap_or() 时,对临时值的引用会传递给函数。如果引用是不可变的,则这不会消耗引用并且分配仍然有效。如果引用是可变引用,unwrap_or() 会消耗该引用,并且不会因为某些临时值而重新借用。
简短的回答是,它在
val3
情况下不起作用,因为这不符合 临时寿命延长的标准。
首先,让我们解决
val2
的情况。 上面的链接中的本节对此进行了介绍:
对于带有初始值设定项的 let 语句,扩展表达式是以下表达式之一:
- ...
- 任何扩展块表达式的最终表达式。
这是匹配块臂的“最终声明”,因此符合标准。 因此,临时的生命周期会延长以匹配
val2
的生命周期。
在
val3
的情况下,它只是不满足条件——列表中不存在函数调用表达式(在文档的以下段落中明确指出)。
那么为什么它在
val1
的情况下有效呢? 由于这需要共享参考而不是专有参考,因此它有资格获得持续促销。
当可以将表达式写入常量、借用并取消引用该借用表达式最初写入的位置而不改变运行时行为时,就会将值表达式提升到
槽。'static
换句话说,它是以下有效的语法糖:
static ZERO: i32 = 0;
let val1 = vec.get(0).unwrap_or(&ZERO);
如果您多次运行此函数,所有
&0
引用将指向相同的实际值,该值将提升为静态持续时间存储。
这不能与独占引用一起使用——独占引用的每个临时对象都需要是唯一的,因为您可以改变它们,因此它们不能仅仅被推入静态持续时间存储中。