为什么在 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
类型的 相同 实例的引用,该实例将存储在可执行文件(或者,从技术上讲,数据部分,如果它包含 Cell
或 AtomicUsize
等)。
在这种情况下,我们可以 "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
.
的引用
我正在学习 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
类型的 相同 实例的引用,该实例将存储在可执行文件(或者,从技术上讲,数据部分,如果它包含 Cell
或 AtomicUsize
等)。
在这种情况下,我们可以 "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
.