首先,下面的代码正确的是:
fn main() {
let a = &get_i32();
println!("{}", a);
}
fn get_i32() -> i32 {
return 100;
}
但是以下代码出现错误:
fn main() {
let a;
a = &get_i32();
println!("{}", a);
}
error[E0716]: temporary value dropped while borrowed
--> src/bin/rust_course.rs:8:10
|
8 | a = &get_i32();
| ^^^^^^^^^- temporary value is freed at the end of this statement
| |
| creates a temporary value which is freed while still in use
9 | println!("{}", a);
| - borrow later used here
|
help: consider using a `let` binding to create a longer lived value
|
8 ~ let binding = get_i32();
9 ~ a = &binding;
|
For more information about this error, try `rustc --explain E0716`.
这两段代码有什么本质区别?我理解&get_i32()
总是返回一个临时值,所以应该总是报错。
类似问题:
fn main() {
let s1 = &String::from("hello world");
println!("{}", s1);
let s2 = String::from("hello world").as_str();
println!("{}", s2);
}
error[E0716]: temporary value dropped while borrowed
--> src/bin/rust_course.rs:6:14
|
6 | let s2 = String::from("hello world").as_str();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary value which is freed while still in use
7 | println!("{}", s2);
| -- borrow later used here
|
help: consider using a `let` binding to create a longer lived value
|
6 ~ let binding = String::from("hello world");
7 ~ let s2 = binding.as_str();
|
For more information about this error, try `rustc --explain E0716`.
s1和s2有什么区别?
还有一个更类似的问题:
fn main() {
print(String::from("hello world").as_str());
}
fn print(str: &str) {
println!("{}", str);
}
上面的代码是正确的,但我不明白为什么String::from("hello world").as_str()
可以传递给函数但不能赋值给变量。
最佳答案
What's the difference between s1 and s2?
答案是temporary lifetime extension 。遗憾的是,这是一个有点非正式的过程(正如页面指出的那样,它可能会发生变化),但从广义上讲,这就是 let
用于绑定(bind)文字引用(因此 &something
)可以触发生命周期延长,其中 something
将得到一个隐式的临时值。所以let a = &get_i32();
和let s1 = &String::from("hello world");
从中受益。
a = &get_i32();
不会,因为 TLE 仅适用于 let
.
let s2 = String::from("hello world").as_str();
也不是,因为临时变量的生命周期延长到语句的末尾,因此链本质上会编译为 block 中的一系列调用,例如:
let s2 = {
let _temp = String::from("hello world");
_temp.as_str()
// _temp is dropped here so `as_str` becomes invalid
};
但是请注意,临时存在于语句的末尾,以防出现
print(String::from("hello world").as_str());
该语句持续到 print
结束为止,本质上:
{
let _temp1 = String::from("hello world");
let _temp2 = _temp1.as_str();
print(_temp2)
};
这完全没问题。
这也是为什么你可以写这样的东西:
match &Some(String::new()).as_deref() {
Some("") => println!("ok"),
Some(_) => println!("??"),
None => println!("ko"),
}
整个match
是单个语句,因此 Option<String>
临时性一直存在到其结束,这意味着我们可以获得对内部和外部值的引用,并使用&Option<&str>
到一个我们从未绑定(bind)到任何地方的值(这是无意义的代码,但它显示了原理,这是我想到的第一件事)。
但是,也有一些情况会导致问题,例如你尝试 match
借用后,将原始值移至其中一个分支。这种情况在非词法生命周期(和借用检查)中已经不太常见,但仍然时不时地发生。
关于rust - 为什么 Rust 的临时值有时是可引用的,有时却不是?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76362527/