Rust生命周期(lifetime)

​ 生命周期的主要目标是避免悬垂引用,它会导致程序引用了非预期引用的数据。当一个值离开作用域时,内存将被释放,这时尝试对该值做任何操作都不能正常工作。

悬垂引用

1
2
3
4
5
6
7
8
9
10
11
12
fn main() {
let reference_to_nothing = dangle();
println!("{}",reference_to_nothing);
}

fn dangle() -> String {
//&String 报错 因为String类型离开了作用域 那么返回值&s将指向一个空地址,因此不用取地址符
let s = String::from("hello");

// &s 报错 因为String类型离开了作用域 那么返回值&s将指向一个空地址,因此不用取地址符
s
}

​ 根据上面的代码可以看到当返回类型为&String时,执行完dangle方法后,内存就被释放,因此reference_to_nothing所引用的值为空。那么,如何解决这类事件的发生呢。

生命周期注解

声明周期注解用来指定声明周期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//fn longest(x: &str, y: &str) -> &str { error
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
//错误!不可以返回函数内部创建的值
// let result = String::from("really long string");
// result.as_str()

fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";

let result = longest(string1.as_str(), string2);
println!("The longest string is {}", result);
}

​ 声明周期注解'a可以理解为返回值&str与参数x或y有着相同的声明周期,因此参数中的引用和返回值之间的就限制是他们都必须拥有相同的生命周期。但是当从函数返回一个引用,返回值的生命周期参数需要与一个参数的生命周期参数相匹配。如果返回的引用没有指向任何一个参数,那么唯一的可能就是它指向一个函数内部创建的值,它将会是一个悬垂引用,因为它将会在函数结束时离开作用域。

结构体生命周期注解

1
2
3
4
5
6
7
8
9
10
11
12
struct ImportantExcerpt<'a> {
part: &'a str,
}

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 };
println!("{}",i.part);
}

结合泛型、trait、生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
}
}

fn main(){
println!("{}",longest_with_an_announcement("1","2",i.part));
}