对从函数返回的临时值的引用

Reference to temporary returned from a function

我在尝试回答 this question 时遇到了这个谜题。

如何/为什么编译:


#[derive(Debug,Default)]
struct Foo {
    i: i32
}

#[derive(Debug)]
struct Bar<'a> {
    foo: &'a Foo
}

impl<'a> Default for Bar<'a> {
    fn default() -> Self {
        Bar {
            foo: &Foo{ i: 25 }
        }
    }
}

fn main() {
    let bar : Bar = Default::default();
    println!("{:?}", bar);
}

Playground

我们创建了一个 Bar 的实例,其中包含对 Foo 的引用,但谁拥有 Foo?它是在 default() 函数中匿名创建的,所以我期待一个错误,指出对它的引用超出了它的范围。

如果我更改 default() 实现,则会收到预期的错误:

    fn default() -> Self {
        let foo = Foo{ i: 25 };
        Bar {
            foo: &foo
        }
    }
error[E0515]: cannot return value referencing local variable `foo`
  --> src/main.rs:15:9
   |
15 | /         Bar {
16 | |             foo: &foo
   | |                  ---- `foo` is borrowed here
17 | |         }
   | |_________^ returns a value referencing data owned by the current function

我阅读了参考文献中与 temporary scopes 相关的部分 - 我没有发现临时对象的范围可以超出函数范围的任何情况。

这是由于 Constant Promotion:

Promotion of a value expression to a 'static slot occurs when the expression could be written in a constant, borrowed, and dereferencing that borrow where the expression was originally written, without changing the runtime behavior. That is, the promoted expression can be evaluated at compile-time and the resulting value does not contain interior mutability or destructors (these properties are determined based on the value where possible, e.g. &None always has the type &'static Option<_>, as it contains nothing disallowed).