为什么在 Rust 中允许返回当前函数拥有的引用?

Why returning a reference owned by the current function is allowed in Rust?

我正在学习 Rust 的 lifetime/ownership 概念,并想解释 Rust (rustc 1.37.0) 中的以下行为。

对于这样的程序:

#[derive(Debug)]
struct Book {
    price: i32,
}

fn main() {
    let book1 = Book {price: 12};
    let cheaper_book = choose_cheaper(&book1);
    println!("{:?}", cheaper_book);
}

fn choose_cheaper(b1: &Book) -> &Book {
    if b1.price < 15 {
        b1
    } else {
        let cheapest_book = Book {price: 0};
        &cheapest_book
    }
}

生锈报告:

17 |   &cheapest_book
   |   ^^^^^^^^^^^^^^ returns a reference to data owned by the current function

我能理解这个错误,因为变量 cheapest_book 是价格为 0 的书的所有者,它会在这个函数结束时被删除,所以返回的引用将变得无效在那之后。但是如果我将 choose_cheaper 函数更改为:

,我很难解释为什么允许以下内容
fn choose_cheaper(b1: &Book) -> &Book {
    if b1.price < 15 {
        b1
    } else {
        let cheapest_book = &Book {price: 0};
        cheapest_book
    }
}

有人能给我一些启发吗?谢谢。

在行 let cheapest_book = &Book {price: 0}; 中,Book 不是 Book 类型的 "new" 实例。每次调用此函数时,它都会 return 对 Book 类型的 相同 实例的引用,该实例将存储在可执行文件(或者,从技术上讲,数据部分,如果它包含 CellAtomicUsize 等)。

在这种情况下,我们可以 "expand" 代码更明确一些:

static GLOBAL_BOOK: Book = Book { price: 0 };

fn choose_cheaper<'a>(b1: &'a Book) -> &'a Book {
    if b1.price < 15 {
        b1
    } else {
        let cheapest_book = &GLOBAL_BOOK;
        cheapest_book
    }
}

请注意,对 GLOBAL_BOOK 的引用实际上可能是 &'static Book,但 &'a Book 是它的超类型,因此 return 静态引用是可以的,就好像这是一个 'a 参考。

如果这看起来很奇怪,请考虑一下这正是字符串文字所发生的事情;他们只是没有明确的 & 字符:在 let foo = "string!"; 之后,foo 是一个 &'static str 引用可执行文件的只读部分中的一些数据,而不是本地目的。所以你也可以在函数 returning &'a str 中为任何 'a.

编写 return "string!";

rust 是否会进行此转换的规则是,每当您 "construct" 一个对象(使用元组语法,或结构或枚举或联合初始化语法,或数字或字符串文字,或它们的任何组合 - not 函数调用 new() 或任何其他函数)在 & 之后,它们将成为匿名静态。所以实际上 &&1_u32 是对静态的 'static 引用 'static 对静态 u32.

的引用