走进Rust:引用的生命周期
Rust大约 3551 字定义
借用检查器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
}
}
阅读 285 · 发布于 2020-07-23
————        END        ————
扫描下方二维码关注公众号和小程序↓↓↓

昵称:
随便看看换一批
- Spring Boot配置文件中设置List和Map阅读 1681
- 监测广告位是否被AdBlock拦截阅读 218
- Spring Boot请求转发和重定向阅读 2057
- Android每隔一分钟发出时间更新广播阅读 1393
- Linux CentOS内核版本2.6升级为4.4阅读 1184
- OpenResty中使用pgmoon连接PostgreSQL阅读 1102
- PostgreSQL使用\copy命令时报character with byte sequence 0xc3 0xa5 in encoding "UTF8" has no equivalent in encoding "GBK"阅读 3039
- Vue mavonEditor 获取 HTML 代码阅读 46
- Python基础语法阅读 344
- Spring Boot Gradle项目添加本地jar包依赖阅读 684