[英]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
类型实例的引用,该引用将存储在可执行文件的只读数据部分(或者,如果包含Cell
或AtomicUsize
或从技术上讲,则存储在该数据部分)类似)。
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.