我正在学习Rust的生存/所有权概念,并想解释一下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的Book的所有者,并且它将在此函数的末尾删除,因此返回的引用在此之后将变为无效。但是,我很难解释为什么如果将choose_cheaper
函数更改为以下内容,为什么允许以下内容:
fn choose_cheaper(b1: &Book) -> &Book {
if b1.price < 15 {
b1
} else {
let cheapest_book = &Book {price: 0};
cheapest_book
}
}
有人可以给我一些启示吗?谢谢。
答案 0 :(得分:7)
在let cheapest_book = &Book {price: 0};
行中,Book
不是{em>不是 Book
类型的“新”实例。每次调用此函数时,它都会返回对Book
类型的 same 实例的引用,该实例将存储在可执行文件的只读数据部分中(或者从技术上讲,数据节中是否包含Cell
或AtomicUsize
等)。
在这种情况下,我们可以将代码“扩展”为更明确的内容:
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
是该引用的超类型,因此可以将静态引用当作{{1 }}参考。
如果这看起来很奇怪,请考虑一下这正是字符串文字所发生的;它们只是没有显式的'a
字符:在&
之后,let foo = "string!";
是foo
,引用可执行文件的只读部分中的某些数据,而不是本地的宾语。因此,您还可以在返回&'static str
的任何return "string!";
函数中编写&'a str
。
是否将进行转换的规则是何时“构造”对象(使用元组语法,结构或枚举或联合初始化语法,数字或字符串文字或它们的任意组合-不是< / strong>函数调用'a
后面的new()
或任何其他函数),它们将成为匿名静态变量。因此,实际上&
是对静态&&1_u32
的静态引用'static
对静态'static
的引用。