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

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 reference says:

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% 准备就绪。

来自Rust Reference

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(),所以它的生命周期在语句结束时结束。