在RUST中,每一个引用都存在有一个lifetime,也就是引用有效的范围,平时情况下,我们可以不去显示的去声明它,但是有些特殊的情况需要显示注明。注明生命周期这种事在其他语言并不存在
使用生命周期方式悬空指针
{
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
} // ---------+
这段代码编译会报错,是因为r这个引用的对象生命周期已经结束了
generic lifetime parameter
fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";
let result = longest(string1.as_str(), string2);
println!("The longest string is {}", result);
}
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
这段代码也是报错的,报错信息如下:
$ cargo run
Compiling chapter10 v0.1.0 (file:///projects/chapter10)
error[E0106]: missing lifetime specifier
--> src/main.rs:9:33
|
9 | fn longest(x: &str, y: &str) -> &str {
| ---- ---- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
help: consider introducing a named lifetime parameter
|
9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
| ++++ ++ ++ ++
For more information about this error, try `rustc --explain E0106`.
error: could not compile `chapter10` due to previous error
主要是代码我们不知道返回的具体是X还是Y,这里我们需要加上生命周期注释
Lifetime Annotation Syntax
首先我们要知道,生命周期注释并不会改变引用的存活时间,它只是描述了不同引用存活时间的关系,注解单个参数并没有任何意义,因为它描述的是一种关系
具体语法是就是’a,'b这种,然后我们看下面的代码
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
这个方法声明表示返回值的生命周期等于入参生命周期最小的一个,如果不符合这个标准,就编译报错
代码1:
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);
}
}
我们可以看到result1和string2的作用域一致,都是比string1小的,所以编译通过
代码2:
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);
}
这个报错,因为result的作用域超过了string2
Lifetime Annotations in Struct Definitions
struct也可以包含引用,我们也需要加上生命周期的注解
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,
};
}
上面代码的意思是ImportantExcerpt的生命周期不能超过part引用的周期
Lifetime Elision
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
像这段代码,参数和返回值都是引用,但是我们没有使用生命周期注解,这是由于rust在某些场景可以推断,它推断的依据在于:
- 形参的生命周期
- 声明返回值的生命周期
- 实际返回的生命周期
这里具体有某些规则
规则1:
有多少个参数,就有多少生命周期,比如
比如:
fn longest(x: &str, y: &str) -> &str {
编译器会识别为:
fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {
但是呢,编译器计算不出返回类型的生命周期,所以编译会报错
规则2:
如果只有一个参数,所有都是它
比如
fn first_word(s: &str) -> &str {
编译器会识别为:
fn first_word<'a>(s: &'a str) -> &'a str {
规则3:
如果方法参数有&self 或者&mut self,那么self的生命周期就会给返回值
The Static Lifetime
'static代表这个引用在整个程序都存在