为什么临时借用是合法的?
Why is it legal to borrow a temporary?
来自 C++,我很惊讶这段代码在 Rust 中有效:
let x = &mut String::new();
x.push_str("Hello!");
在 C++ 中,您不能获取临时地址,并且临时地址不会超过它所在的表达式。
临时在 Rust 中存在多长时间?由于 x
只是借用,那么字符串的所有者是谁?
Why is it legal to borrow a temporary?
它合法的原因与它在 C++ 中非法的原因相同 — because someone said that's how it should be。
How long does the temporary live in Rust? And since x
is only a borrow, who is the owner of the string?
the temporary scope of an expression is the
smallest scope that contains the expression and is for one of the following:
- The entire function body.
- A statement.
- The body of a
if
, while
or loop
expression.
- The
else
block of an if
expression.
- The condition expression of an
if
or while
expression, or a match
guard.
- The expression for a match arm.
- The second operand of a lazy boolean expression.
基本上,您可以将代码视为:
let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
另请参阅:
Rust 的 MIR 提供了一些关于临时对象本质的见解;考虑以下简化情况:
fn main() {
let foo = &String::new();
}
及其生成的 MIR(标准注释替换为我的):
fn main() -> () {
let mut _0: ();
scope 1 {
let _1: &std::string::String; // the reference is declared
}
scope 2 {
}
let mut _2: std::string::String; // the owner is declared
bb0: {
StorageLive(_1); // the reference becomes applicable
StorageLive(_2); // the owner becomes applicable
_2 = const std::string::String::new() -> bb1; // the owner gets a value; go to basic block 1
}
bb1: {
_1 = &_2; // the reference now points to the owner
_0 = ();
StorageDead(_1); // the reference is no longer applicable
drop(_2) -> bb2; // the owner's value is dropped; go to basic block 2
}
bb2: {
StorageDead(_2); // the owner is no longer applicable
return;
}
}
您可以看到,"invisible" 所有者在将引用分配给它之前收到一个值,并且引用在所有者之前被删除,正如预期的那样。
我不确定的是为什么有一个看似无用的 scope 2
以及为什么所有者没有被放入任何范围内;我怀疑 MIR 还没有 100% 准备就绪。
Temporary lifetimes
When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead
这适用,因为 String::new()
是一个值表达式,并且就在 &mut
下面,它在一个地方表达式上下文中。现在引用运算符只需要经过这个临时内存位置,就变成了整个右边的值(包括&mut
)。
When a temporary value expression is being created that is assigned into a let declaration, however, the temporary is created with the lifetime of the enclosing block instead
由于它被分配给变量,因此它的生命周期一直持续到封闭块结束。
这也回答了 this question 关于
之间的区别
let a = &String::from("abcdefg"); // ok!
和
let a = String::from("abcdefg").as_str(); // compile error
在第二个变体中,临时变量被传递到 as_str()
,所以它的生命周期在语句结束时结束。
来自 C++,我很惊讶这段代码在 Rust 中有效:
let x = &mut String::new();
x.push_str("Hello!");
在 C++ 中,您不能获取临时地址,并且临时地址不会超过它所在的表达式。
临时在 Rust 中存在多长时间?由于 x
只是借用,那么字符串的所有者是谁?
Why is it legal to borrow a temporary?
它合法的原因与它在 C++ 中非法的原因相同 — because someone said that's how it should be。
How long does the temporary live in Rust? And since
x
is only a borrow, who is the owner of the string?
the temporary scope of an expression is the smallest scope that contains the expression and is for one of the following:
- The entire function body.
- A statement.
- The body of a
if
,while
orloop
expression.- The
else
block of anif
expression.- The condition expression of an
if
orwhile
expression, or amatch
guard.- The expression for a match arm.
- The second operand of a lazy boolean expression.
基本上,您可以将代码视为:
let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
另请参阅:
Rust 的 MIR 提供了一些关于临时对象本质的见解;考虑以下简化情况:
fn main() {
let foo = &String::new();
}
及其生成的 MIR(标准注释替换为我的):
fn main() -> () {
let mut _0: ();
scope 1 {
let _1: &std::string::String; // the reference is declared
}
scope 2 {
}
let mut _2: std::string::String; // the owner is declared
bb0: {
StorageLive(_1); // the reference becomes applicable
StorageLive(_2); // the owner becomes applicable
_2 = const std::string::String::new() -> bb1; // the owner gets a value; go to basic block 1
}
bb1: {
_1 = &_2; // the reference now points to the owner
_0 = ();
StorageDead(_1); // the reference is no longer applicable
drop(_2) -> bb2; // the owner's value is dropped; go to basic block 2
}
bb2: {
StorageDead(_2); // the owner is no longer applicable
return;
}
}
您可以看到,"invisible" 所有者在将引用分配给它之前收到一个值,并且引用在所有者之前被删除,正如预期的那样。
我不确定的是为什么有一个看似无用的 scope 2
以及为什么所有者没有被放入任何范围内;我怀疑 MIR 还没有 100% 准备就绪。
Temporary lifetimes
When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead
这适用,因为 String::new()
是一个值表达式,并且就在 &mut
下面,它在一个地方表达式上下文中。现在引用运算符只需要经过这个临时内存位置,就变成了整个右边的值(包括&mut
)。
When a temporary value expression is being created that is assigned into a let declaration, however, the temporary is created with the lifetime of the enclosing block instead
由于它被分配给变量,因此它的生命周期一直持续到封闭块结束。
这也回答了 this question 关于
之间的区别let a = &String::from("abcdefg"); // ok!
和
let a = String::from("abcdefg").as_str(); // compile error
在第二个变体中,临时变量被传递到 as_str()
,所以它的生命周期在语句结束时结束。