Rust lifecycle
Rust lifecycle mechanism is a resource management mechanism as important as ownership mechanism.
The reason why this concept is introduced is to deal with the problem of resource management in complex type systems.
Reference is an indispensable mechanism when dealing with complex types, after all, complex type data cannot be easily copied and calculated by the processor.
But references often lead to extremely complex resource management problems,so first take a look at overhanging references:
Example
{
let r;
{
let x = 5;
r = &x;
}
println!("r: {}", r);
}
This code will not pass the Rust compiler because the value referenced by r has been released before it is used.
The green range’an in the figure above represents the life cycle of r and the blue range’b represents the life cycle of x. Obviously,’b is much smaller than’a, and the reference must be within the lifetime of the value to be valid.
We’ve always used it in structures. String
without having to &str
, let’s use a case to explain why:
Example
fn longer(s1: &str, s2: &str) -> &str {
if s2.len() > s1.len() {
s2
} else {
s1
}
}
longer
function takes the longer of the two string slices S1 and S2 and returns its reference value. But only this code will not be compiled because the return value reference may return an expired reference:
Example
fn main() {
let r;
{
let s1 = "rust";
let s2 = "ecmascript";
r = longer(s1, s2);
}
println!("{} is longer", r);
}
Although this program has been compared, the source values S1 and S2 are invalid when r is used. Of course, we can move the use of r to the life cycle of S1 and S2 to prevent this error from happening, but for the function, it does not know what is going on outside itself. In order to ensure that the value it passes out is normal, it must choose the ownership principle to eliminate all dangers, so the longer
function cannot be compiled.
Lifecycle comment
Lifecycle annotations are a way to describe reference lifecycles.
Although this does not change the lifecycle of the reference, you can declare that the lifecycle of the two references is the same in the appropriate place.
Lifecycle comments begin with single quotation marks, followed by a lowercase word:
&I32//General reference
&'a i32//References containing lifecycle annotations
&'a mut i32//Variable references with lifecycle annotations
Let’s transform with lifecycle annotations longer
function:
Example
fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if s2.len() > s1.len() {
s2
} else {
s1
}
}
We need to standardize the name of the life cycle with a generic declaration, and then the life cycle of the return value of the function will be the same as the life cycle of the two parameters, so you can write this when calling:
Example
fn main() {
let r;
{
let s1 = "rust";
let s2 = "ecmascript";
r = longer(s1, s2);
println!("{} is longer", r);
}
}
The running result of the combination of the above two programs:
ecmascript is longer
Note: don’t forget the principle of automatic type determination.
Using string slice references in structures
This is the question left before, and here is the answer:
Example
fn main() {
struct Str<'a> {
content: &'a str
}
let s = Str {
content: "string_slice"
};
println!("s.content = {}", s.content);
}
Running result:
s.content = string_slice
If the structure Str
has methods to define:
Example
impl<'a> Str<'a> {
fn get_content(&self) -> &str {
self.content
}
}
The return value here has no lifecycle comments, but it doesn’t hurt to add it. This is a historical issue. Early Rust did not support automatic lifecycle judgment, and all lifecycles must be strictly declared, but mainstream stable versions of Rust already support this feature.
Static life cycle
The lifecycle annotation has a special feature: 'static
. The exact data type represented by all string constants enclosed in double quotation marks is &'static str
, and the lifecycle represented by 'static
is from the start of program operation to the end of program operation.
Generics, features, and lifecycle work together
Example
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
}
}
This program comes from the Rust Bible, is a program that uses generics, features, and life cycle mechanisms at the same time. It is not required, itcan be experienced, after all, it can be used sooner or later!