简体   繁体   English

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

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

I am learning Rust's lifetime/ownership concepts, and would like to explain the following behavior in Rust (rustc 1.37.0). 我正在学习Rust的寿命/所有权概念,并想解释一下Rust(rustc 1.37.0)中的以下行为。

For a program like this: 对于这样的程序:

#[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
    }
}

Rust reports: 锈报告:

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

And I can understand this error and it is because variable cheapest_book is the owner of the Book with price 0, and it will be dropped at the end of this function, so the returned reference will become invalid after that. 而且我可以理解此错误,这是因为变量cheapest_book是价格为0的Book的所有者,并且它将在此函数结束时删除,因此返回的引用在此之后将变为无效。 But it is hard for me to explain why the following is allowed if I change the choose_cheaper function to be: 但是,对于我来说,很难解释为什么如果将choose_cheaper函数更改为以下内容,为什么允许以下操作:

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

Could some one shed me some light on it? 可以给我一些启示吗? Thanks. 谢谢。

In the line let cheapest_book = &Book {price: 0}; 在这一行中, let cheapest_book = &Book {price: 0}; , the Book is not a "new" instance of the Book type. ,则Book 不是 Book类型的“新”实例。 Every time this function is called it will return a reference to the same instance of the Book type, which will be stored in the read-only data section of the executable (or, technically, the data section if it contains a Cell or AtomicUsize or the like). 每次调用此函数时,它都会返回对相同 Book类型实例的引用,该引用将存储在可执行文件的只读数据部分(或者,如果包含CellAtomicUsize或从技术上讲,则存储在该数据部分)类似)。

We can in this instance "expand" the code into something a little more explicit: 在这种情况下,我们可以将代码“扩展”为更明确的内容:

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
    }
}

Note that the reference to GLOBAL_BOOK could actually be a &'static Book , but &'a Book is a supertype of that so it's okay to return the static reference as if it were an 'a reference. 请注意,对GLOBAL_BOOK的引用实际上可以是&'static Book ,但&'a Book&'a Book的超类型,因此可以将静态引用当作是'a引用来返回。

If this seems weird, consider that this is exactly what happens with string literals; 如果这看起来很奇怪,请考虑一下这正是字符串文字所发生的; they just don't have the explicit & character: After let foo = "string!"; 它们只是没有显式&字符: let foo = "string!"; , foo is a &'static str referencing some data in the read-only section of the executable, not a local object. foo&'static str引用可执行文件的只读部分中的某些数据,而不是本地对象。 So you can also write return "string!"; 这样您还可以编写return "string!"; in functions returning &'a str for any 'a . 在函数返回&'a str为任何'a

The rule for whether rust will make this transformation is whenever you "construct" an object (using tuple syntax, or struct or enum or union initialization syntax, or numeric or string literals, or any combinations thereof - not function calls to new() or any other function) behind a & , they'll become an anonymous static. 生锈是否进行此转换的规则是您“构造”对象时(使用元组语法,结构或枚举或联合初始化语法,数字或字符串文字或它们的任意组合- 而不是new()函数调用或&后面的任何其他函数),它们将成为匿名静态变量。 So in fact &&1_u32 is a 'static reference to a static 'static reference to a static u32 . 所以其实&&1_u32'static参考静态'static参考静态u32

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM