提问人:artzok 提问时间:5/30/2023 更新时间:5/30/2023 访问量:120
为什么 Rust 的临时值有时是引用的,有时不是?
Why are temporary values of Rust sometimes referential and sometimes not?
问:
首先,以下代码是正确的:
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()
答:
s1 和 s2 有什么区别?
答案是暂时延长寿命。可悲的是,这是一个有点非正式的过程(正如页面所指出的那样,它可能会发生变化),但从广义上讲,它用于绑定文字引用(因此)可以触发生命周期延长,其中将获得隐式临时引用。因此,并从中受益。let
&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();
也没有,因为临时的生命周期被延长到语句的末尾,所以链本质上编译为块中的一系列调用,例如:
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>
但是,在某些情况下,如果尝试借入,然后将原始值移动到其中一个分支中,则会导致问题。这在非词法生存期(和借用检查)中已经不那么常见了,但它仍然不时发生。match
评论