为什么借临时是合法的?

时间:2017-12-05 20:36:41

标签: rust temporary

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

let x = &mut String::new();
x.push_str("Hello!");

在C ++中,你不能获取临时的地址,并且暂时胜过它所出现的表达式。

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

3 个答案:

答案 0 :(得分:15)

  

为什么借用临时合法是合法的?

这是合法的,因为它在C ++中是非法的 - because someone said that's how it should be

  

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

The reference says

  

临时值的生命周期通常为

     
      
  • 最里面的封闭声明;块的尾部表达式是   被认为是封闭该区块的陈述的一部分,或
  •   
  • 的   条件表达式或循环条件表达式,如果   临时是在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)

来自Rust Reference

  

临时生命期

     

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

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

  

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

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

这也回答this question关于

之间的区别
let a = &String::from("abcdefg"); // ok!

let a = String::from("abcdefg").as_str(); // compile error

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