走进 Rust:引用的生命周期
Rust About 3,552 words定义
借用检查器borrow checker
会比较作用域来确保所有的引用都是有效的。
x
的引用的生命周期是'b
,即r = &x;
后引用就被回收了,而r
指向了x
的引用,但在'b
作用域后r
指向的是一个被回收的地址,形成了类似于Java
中的null
,这在Rust
中是不允许的。
{
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
} // ---------+
会得到错误
error[E0597]: `x` does not live long enough
--> src/main.rs:7:5
|
6 | r = &x;
| - borrow occurs here
7 | }
| ^ `x` dropped here while still borrowed
...
10 | }
| - borrowed value needs to live until here
语法
&i32 // 引用
&'a i32 // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用
生命周期省略规则
函数或方法的参数的生命周期被称为输入生命周期
。
返回值的生命周期被称为输出生命周期
。
第一条规则
有一个引用参数的函数有一个生命周期参数:
fn foo<'a>(x: &'a i32) {}
有两个引用参数的函数有两个不同的生命周期参数。
fn foo<'a, 'b>(x: &'a i32, y: &'b i32) {}
第二条规则
如果只有一个输入生命周期参数,那么输出生命周期参数就等于输入生命周期参数。
fn foo<'a>(x: &'a i32) -> &'a i32
第三条规则
如果方法有多个输入生命周期参数,不过其中之一因为方法的缘故为 &self 或 &mut self,那么 self 的生命周期被赋给所有输出生命周期参数。
fn level(&self) -> i32 {}
函数中的引用生命周期
函数中的名称以及入参和返回值都标注有生命周期参数'a
。
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
错误调用:此处的longest
函数的返回值被指向了result
,而longest
函数的返回值在内部大括号作用域结束后已经被回收,导致在println
时再次引用出现问题。(没有println
这句代码编译能通过。)
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
}
println!("The longest string is {}", result);
}
// 错误信息
error[E0597]: `string2` does not live long enough
--> src/main.rs:15:5
|
14 | result = longest(string1.as_str(), string2.as_str());
| ------- borrow occurs here
15 | }
| ^ `string2` dropped here while still borrowed
16 | println!("The longest string is {}", result);
17 | }
| - borrowed value needs to live until here
正确调用:
fn main() {
let string1 = String::from("long string is long");
{
let string2 = String::from("xyz");
let result = longest(string1.as_str(), string2.as_str());
println!("The longest string is {}", result);
}
}
结构体中的引用生命周期
定义字段中包含引用生命周期的结构体。
struct ImportantExcerpt<'a> {
part: &'a str,
}
使用该结构体。注意:ImportantExcerpt
实例的作用域要小于等于part
引用的作用域。
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.')
.next()
.expect("Could not find a '.'");
let i = ImportantExcerpt { part: first_sentence };
}
方法中的引用生命周期
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
}
impl<'a> ImportantExcerpt<'a> {
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention please: {}", announcement);
self.part
}
}
静态生命周期
'static
,其生命周期能够存活于整个程序期间。
let s: &'static str = "I have a static lifetime.";
综合示例
结合泛型类型参数、trait bounds
和生命周期
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
where T: Display
{
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓