为什么借临时是合法的?

Sve*_*ach 13 temporary rust

来自C++,我很惊讶这段代码在Rust中是有效的:

let x = &mut String::new();
x.push_str("Hello!");
Run Code Online (Sandbox Code Playgroud)

在C++中,你不能取一个临时的地址,一个临时的不会比它出现的表达式更长.

临时居住在Rust多久了?既然x只是借用,谁是字符串的所有者?

She*_*ter 16

为什么借临时是合法的?

这是合法的,因为它在C++中是非法的 - 因为有人说它应该是这样的.

临时居住在Rust多久了?既然x只是借用,谁是字符串的所有者?

参考文献说:

临时值的生命周期通常是

  • 最里面的封闭声明; 块的尾部表达式被认为是包含块的语句的一部分,或者
  • 条件表达式或如果临时环路的条件表达式中的条件表达式创建ifif/ else或在loop一段时间表达式的条件表达式.

但是,当创建一个分配给let 声明的临时rvalue 时,临时是使用封闭块的生命周期创建的,因为使用封闭语句(let 声明)将是一个保证错误(因为指向临时的指针)将存储到变量中,但在使用变量之前将释放临时值.编译器使用简单的语法规则来决定将哪些值分配给let绑定,因此需要更长的临时生命周期.

基本上,您可以将代码视为:

let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
Run Code Online (Sandbox Code Playgroud)

也可以看看:


sta*_*lue 6

来自Rust参考:

临时生命

在大多数场所表达式上下文中使用值表达式时,会创建一个初始化为该值的临时未命名内存位置,而表达式将计算到该位置而不是

这是适用的,因为它String::new()是一个值表达式,并且&mut位于地下表达式上下文中.现在引用操作符只需要通过这个临时内存位置,因此它成为整个右侧的值(包括&mut).

但是,当创建分配给let声明的临时值表达式时,将使用封闭块的生存期创建临时值

由于它被赋值给变量,因此它会在封闭块结束之前获得生命周期.

这也回答了这个问题有关的区别

let a = &String::from("abcdefg"); // ok!
Run Code Online (Sandbox Code Playgroud)

let a = String::from("abcdefg").as_str(); // compile error
Run Code Online (Sandbox Code Playgroud)

在第二个变体中,临时传递as_str(),因此它的生命周期在语句结束时结束.


lje*_*drz 5

Rust的MIR提供了一些关于临时性质的见解; 考虑以下简化案例:

fn main() {
    let foo = &String::new();
}
Run Code Online (Sandbox Code Playgroud)

它产生的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以看到"不可见"所有者在为其分配引用之前收到一个值,并且该引用在所有者之前被删除,如预期的那样.

我不确定的是为什么有一个看似无用的东西scope 2以及为什么所有者不被置于任何范围内; 我怀疑MIR还没有100%准备就绪.