5.10 Life Cycle
This section is one of the three parts of rust that describes the ownership system. Ownership is the most unique and compelling feature of Rust, a feature that rust programmers must be familiar with. Ownership allows Rust to achieve its greatest design goal, memory security. Here are some different concepts, each with its own chapters:
- Ownership that you're reading
- Borrowing (borrowing, 5.9), and its associated attribute ' references '
- Lifetime (5.10), and advanced features of borrowing
These three are relevant and gradual. You have to fully understand this three-part.
5.10.1 USD
Before we discuss the details, there are two important notes about the ownership system.
Rust is committed to security and fast. It achieves this by "0 spent abstraction (zero-cost abstractions)", which means that abstraction costs the least in rust. All the analysis we discussed in this chapter is done at compile time. You don't have to worry about running-time overhead. .
However, the system still has some overhead: the learning curve. Many of Rust's beginners will experience us as a "fight against borrowing and testing." Process. That is, the rust compiler refuses to compile code that programmers think is available. Because the programmer's idea of ownership is often in conflict with the real rust rules. You will try to do something similar at the beginning. But that's good news, More experienced rust programmers feedback that once they have adapted to this rule for a period of time, they will struggle less and fewer.
With this cushion, we come to learn the life time.
5.10.2 life cycle
Lending a reference to a resource that is being used can cause chaos. For example, consider this:
- I'm requesting a handle to a resource of some kind
- I lent you a reference to this resource
- I decided that I'd run out of this resource, release it, and you're still using this reference
- You decide to use this resource
Oh! your reference points to an invalid resource. This is called a hover pointer, or "Use after release" when the resource is memory. To solve this problem, we need to make sure that the fourth step does not occur after the third step. Rust's ownership system is implemented through lifetimes, which describe the scope in which the reference applies.
When we have a function with a reference parameter, we implicitly or explicitly become the lifetime of the reference:
Implicit
fn foo (x: &i32) {
}
Explicit
fn bar< ' a> (x: & ' a i32) {
}
' A read for life A. Technically, every reference has a lifetime, but the compiler allows you to ignore them. Let's take a look at the example shown:
fn bar< ' a> (...)
In our parameter list, we use our name:
... (x: & ' a i32)
If we use a &mut reference, we will:
... (x: & ' a mut i32)
If you compare &mut i32 and & ' A mut i32, they are the same, only ' a ' is inserted between & and mute i32. We read &mut i32 as "A variable reference to I32" and Read & ' a mut i32 as "A mutable reference to I32, with a lifetime of ' A."
When you use a struct you also need to have an explicit lifetime: struct foo< ' a>} x: & ' A i32,}
fn Main () {Let y = &5;//and ' let _y = 5; let y = &_y; ' Same as let F = Foo {x:y}; println! ("{}", f.x);} As you can see, structs also has a life cycle. The function has the same form,
struct foo< ' a> {declares a lifetime ' A, and
X: & ' A i32,
Used it. Why do we need life? We need to make sure that any reference to Foo cannot survive longer than the one I32 reference it contains.
Consider the scope:
One way to think about life is to have a virtual reference available scope. For example:
fn Main () {
Let y = &5;//-+ y Enter scope
// |
Stuff//|
// |
}//-+ y leave scope
Add Foo:
struct foo< ' a> {x: & ' A i32,}
fn Main () {
Let y = &5; -+ y Enter scope
Let F = Foo {x:y}; -+ F Enter Scope
Stuff//|
// |
}//-+ Y and F both leave scope
F lives in the scope of Y, so everything is fine. What if it's not? This code does not work:
struct foo< ' a> {
X: & ' A i32,
}
fn Main () {
Let X; -+ x goes into scope
// |
{ // |
Let y = &5; ---+ y goes into scope let F = Foo {x:y};//---+ f goes into scope
x = &f.x; // | | Error here
}//---+ F and y go out of scope
// |
println! ("{}", x); // |
}//-+ x goes out of scope
Wow! as you can see, F and Y are smaller than the scope of X. When we x = &f.x, we create a reference to the object beyond its scope.
A named lifetime is a name that has this scope. This is the first step.
' Static
The static life period is a special life period. It means that something has a lifetime of the whole program. Most rust programmers use the ' static ' string for the first time:
Let x: & ' static str = ' Hello, world ';
string literal constants have the & ' static str type because the references always exist: they will exist in the data segment of the last binary. Another example is a global variable:
Static FOO:I32 = 5;let x: & ' static I32 = &FOO;
Add a i32 to the data segment of the binary file, and then X is a reference to it.
Life-Time Omission:
Rust provides a strong local type reference in the function body. However, this cannot be used in the signature of the type deduction. However, for ergonomics reasons, a very strict secondary derivation algorithm "life-time ellipsis" can be applied to function signatures. It only works in function signatures, not in function bodies, Only acting on the lifetime parameters, there are three well-remembered clear rules. This makes life-time ellipsis a short board for writing function signatures, and not hiding the true type can result in a complete local type deduction.
When discussing life-time ellipsis, we use terminology to enter life and output lifetimes. The input lifetime is the life period associated with the function parameter, and the output lifetime is the life period associated with the return value. For example, this function has an input lifetime:
fn foo< ' a> (bar: & ' a str)
This has an output lifetime:
fn foo< ' a> & ' a str
This has output and input lifetimes:
fn foo< ' a> (bar: & ' a str) & ' a str
Here are three rules:
- The omitted lifetime in each function parameter becomes a definite life-time parameter
- If there is an input lifetime, whether or not omitted, his lifetime is assigned to all the omitted lifetimes in the function return value
- If there are multiple input lifetimes, one of which is the lifetime of &self or &mut self,self will be assigned to all omitted output lifetimes
Otherwise, there will be an error pointing to an omitted output lifetime
Example: Here are some examples of omitting lifetimes. We paired each example to show the live version and the expanded version
fn Print (s: &str); elided
fn print< ' a> (S: & ' a str); Expanded
fn Debug (lvl:u32, S: &str); elided
fn debug< ' a> (lvl:u32, S: & ' a str); Expanded
In the preceding example, ' LVL ' doesn?t need a lifetime because it?s not a
Reference (' & '). Only things relating to references (such as a ' struct '//which contains a reference) need lifetimes.
FN substr (s: &str, until:u32) &str; elided
fn substr< ' a> (S: & ' a str, until:u32) & ' a str; Expanded
&str; fn GET_STR () Illegal, no inputs
FN Frob (s: &str, T: &str) &str; Illegal, inputs
FN frob< ' A, ' b> (s: & ' A str, T: & ' b str) &str; Expanded:output Lifetime is unclear
fn Get_mut (&mut self), &mut T; elided
fn get_mut< ' a> (& ' a mut self) & ' a mut T; Expanded
fn args<t:tocstr> (&mut self, args: &[t]), &mut Command//elided
FN args< ' A, ' B, t:tocstr> (& ' A mut self, args: & ' B [T]), & ' a mut Command//Expanded
fn New (buf: &mut [U8]), Bufwriter; elided
fn new< ' a> (buf: & ' A mut [U8]), bufwriter< ' a>//Expanded
Rust Chinese Translation 29