来自C ++,我很惊讶这段代码在Rust中有效:
let x = &mut String::new();
x.push_str("Hello!");
在C ++中,你不能获取临时的地址,并且暂时胜过它所出现的表达式。
临时住在Rust多久了?由于x
只是借用,谁是字符串的所有者?
答案 0 :(得分:15)
为什么借用临时合法是合法的?
这是合法的,因为它在C ++中是非法的 - because someone said that's how it should be。
临时住在Rust多久了?由于
x
只是借用,谁是字符串的所有者?
临时值的生命周期通常为
- 最里面的封闭声明;块的尾部表达式是 被认为是封闭该区块的陈述的一部分,或
- 的 条件表达式或循环条件表达式,如果 临时是在
if
的条件表达式中创建的if
/else
或while表达式的loop
条件表达式。当创建分配到
let
的临时右值时 但是,声明是在生命周期中创建的 相反,使用封闭语句(let
声明)将是一个保证错误(因为指向 临时存储到变量中,但临时存储 在可以使用变量之前释放)。编译器使用简单 语法规则决定将哪些值分配给let 绑定,因此应该有更长的临时生命。
基本上,您可以将代码视为:
let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
另见:
答案 1 :(得分:5)
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;
}
}
您可以看到“不可见”所有者在为其分配引用之前收到一个值,并且在所有者之前删除了引用,如预期的那样。
我不确定的是为什么有一个看似无用的scope 2
以及为什么所有者不被置于任何范围内;我怀疑MIR还没有100%准备就绪。
答案 2 :(得分:5)
临时生命期
在大多数场所表达式上下文中使用值表达式时,会创建一个初始化为该值的临时未命名内存位置,而表达式将计算到该位置
这适用,因为String::new()
是一个值表达式,并且位于&mut
之下,它位于地方表达式上下文中。现在,引用运算符只需要通过这个临时内存位置,因此它将成为整个右侧的值(包括&mut
)。
但是,当创建一个分配给let声明的临时值表达式时,将使用封闭块的生命周期创建临时值
由于它被赋值给变量,因此它会在封闭块结束之前获得生命周期。
这也回答this question关于
之间的区别let a = &String::from("abcdefg"); // ok!
和
let a = String::from("abcdefg").as_str(); // compile error
在第二个变体中,临时值被传递到as_str()
,因此它的生命周期在语句结束时结束。