nyb*_*bon 3 struct initialization lifetime ownership rust
我正在学习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
}
}
Run Code Online (Sandbox Code Playgroud)
Rust报告:
17 | &cheapest_book
| ^^^^^^^^^^^^^^ returns a reference to data owned by the current function
Run Code Online (Sandbox Code Playgroud)
而且我可以理解该错误,这是因为变量cheapest_book是价格为0的Book的所有者,并且将在此函数的结尾将其删除,因此之后返回的引用将变为无效。但是,我很难解释为什么将choose_cheaper函数更改为以下内容时可以使用以下内容:
17 | &cheapest_book
| ^^^^^^^^^^^^^^ returns a reference to data owned by the current function
Run Code Online (Sandbox Code Playgroud)
可以给我一些启示吗?谢谢。
小智 7
在线路let cheapest_book = &Book {price: 0};中,Book是不是在一个“新”的实例Book类型。每次调用此函数时,它将返回对该类型相同实例的引用,该引用Book将存储在可执行文件的只读数据部分中(或者,如果包含a 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
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,对的引用GLOBAL_BOOK实际上可能是&'static Book,但是&'a Book是该引用的超类型,因此可以将静态引用当作引用一样返回'a。
如果这看起来很奇怪,请考虑一下这正是字符串文字所发生的;它们只是没有显式的&字符:在之后let foo = "string!";,foo是&'static str对可执行文件的只读部分中的某些数据的引用,而不是本地对象。因此,您还可以编写return "string!";返回&'a strany的函数'a。
生锈是否进行此转换的规则是您“构造”一个对象时(使用元组语法,结构或枚举或联合初始化语法,数字或字符串文字或它们的任意组合,而不是函数调用new()或任何其他函数) )&,它们将成为匿名静态对象。因此,实际上&&1_u32是'static对static的'static引用u32。