]> git.lizzy.rs Git - rust.git/blob - src/doc/tarpl/lifetimes.md
37d035733613941bc339b0352d6c0b20f8520f24
[rust.git] / src / doc / tarpl / lifetimes.md
1 % Lifetimes
2
3 Rust enforces these rules through *lifetimes*. Lifetimes are effectively
4 just names for scopes somewhere in the program. Each reference,
5 and anything that contains a reference, is tagged with a lifetime specifying
6 the scope it's valid for.
7
8 Within a function body, Rust generally doesn't let you explicitly name the
9 lifetimes involved. This is because it's generally not really *necessary*
10 to talk about lifetimes in a local context; Rust has all the information and
11 can work out everything as optimally as possible. Many anonymous scopes and
12 temporaries that you would otherwise have to write are often introduced to
13 make your code *just work*.
14
15 However once you cross the function boundary, you need to start talking about
16 lifetimes. Lifetimes are denoted with an apostrophe: `'a`, `'static`. To dip
17 our toes with lifetimes, we're going to pretend that we're actually allowed
18 to label scopes with lifetimes, and desugar the examples from the start of
19 this chapter.
20
21 Originally, our examples made use of *aggressive* sugar -- high fructose corn
22 syrup even -- around scopes and lifetimes, because writing everything out
23 explicitly is *extremely noisy*. All Rust code relies on aggressive inference
24 and elision of "obvious" things.
25
26 One particularly interesting piece of sugar is that each `let` statement implicitly
27 introduces a scope. For the most part, this doesn't really matter. However it
28 does matter for variables that refer to each other. As a simple example, let's
29 completely desugar this simple piece of Rust code:
30
31 ```rust
32 let x = 0;
33 let y = &x;
34 let z = &y;
35 ```
36
37 The borrow checker always tries to minimize the extent of a lifetime, so it will
38 likely desugar to the following:
39
40 ```rust,ignore
41 // NOTE: `'a: {` and `&'b x` is not valid syntax!
42 'a: {
43     let x: i32 = 0;
44     'b: {
45         // lifetime used is 'b because that's *good enough*.
46         let y: &'b i32 = &'b x;
47         'c: {
48             // ditto on 'c
49             let z: &'c &'b i32 = &'c y;
50         }
51     }
52 }
53 ```
54
55 Wow. That's... awful. Let's all take a moment to thank Rust for being a
56 diabetes-inducing torrent of syrupy-goodness.
57
58 Actually passing references to outer scopes will cause Rust to infer
59 a larger lifetime:
60
61 ```rust
62 let x = 0;
63 let z;
64 let y = &x;
65 z = y;
66 ```
67
68 ```rust,ignore
69 'a: {
70     let x: i32 = 0;
71     'b: {
72         let z: &'b i32;
73         'c: {
74             // Must use 'b here because this reference is
75             // being passed to that scope.
76             let y: &'b i32 = &'b x;
77             z = y;
78         }
79     }
80 }
81 ```
82
83
84
85 # Example: references that outlive referents
86
87 Alright, let's look at some of those examples from before:
88
89 ```rust,ignore
90 fn as_str(data: &u32) -> &str {
91     let s = format!("{}", data);
92     &s
93 }
94 ```
95
96 desugars to:
97
98 ```rust,ignore
99 fn as_str<'a>(data: &'a u32) -> &'a str {
100     'b: {
101         let s = format!("{}", data);
102         return &'a s;
103     }
104 }
105 ```
106
107 This signature of `as_str` takes a reference to a u32 with *some* lifetime, and
108 promises that it can produce a reference to a str that can live *just as long*.
109 Already we can see why this signature might be trouble. That basically implies
110 that we're going to *find* a str somewhere in the scope the scope the reference
111 to the u32 originated in, or somewhere *even* earlier. That's a *bit* of a big ask.
112
113 We then proceed to compute the string `s`, and return a reference to it. Since
114 the contract of our function says the reference must outlive `'a`, that's the
115 lifetime we infer for the reference. Unfortunately, `s` was defined in the
116 scope `'b`, so the only way this is sound is if `'b` contains `'a` -- which is
117 clearly false since `'a` must contain the function call itself. We have therefore
118 created a reference whose lifetime outlives its referent, which is *literally*
119 the first thing we said that references can't do. The compiler rightfully blows
120 up in our face.
121
122 To make this more clear, we can expand the example:
123
124 ```rust,ignore
125 fn as_str<'a>(data: &'a u32) -> &'a str {
126     'b: {
127         let s = format!("{}", data);
128         return &'a s
129     }
130 }
131
132 fn main() {
133     'c: {
134         let x: u32 = 0;
135         'd: {
136             // An anonymous scope is introduced because the borrow does not
137             // need to last for the whole scope x is valid for. The return
138             // of as_str must find a str somewhere *before* this function
139             // call. Obviously not happening.
140             println!("{}", as_str::<'d>(&'d x));
141         }
142     }
143 }
144 ```
145
146 Shoot!
147
148 Of course, the right way to write this function is as follows:
149
150 ```rust
151 fn to_string(data: &u32) -> String {
152     format!("{}", data)
153 }
154 ```
155
156 We must produce an owned value inside the function to return it! The only way
157 we could have returned an `&'a str` would have been if it was in a field of the
158 `&'a u32`, which is obviously not the case.
159
160 (Actually we could have also just returned a string literal, which as a global
161 can be considered to reside at the bottom of the stack; though this limits
162 our implementation *just a bit*.)
163
164
165
166
167
168 # Example: aliasing a mutable reference
169
170 How about the other example:
171
172 ```rust,ignore
173 let mut data = vec![1, 2, 3];
174 let x = &data[0];
175 data.push(4);
176 println!("{}", x);
177 ```
178
179 ```rust,ignore
180 'a: {
181     let mut data: Vec<i32> = vec![1, 2, 3];
182     'b: {
183         // 'b is as big as we need this borrow to be
184         // (just need to get to `println!`)
185         let x: &'b i32 = Index::index::<'b>(&'b data, 0);
186         'c: {
187             // Temporary scope because we don't need the
188             // &mut to last any longer.
189             Vec::push(&'c mut data, 4);
190         }
191         println!("{}", x);
192     }
193 }
194 ```
195
196 The problem here is is bit more subtle and interesting. We want Rust to
197 reject this program for the following reason: We have a live shared reference `x`
198 to a descendent of `data` when try to take a *mutable* reference to `data`
199 when we call `push`. This would create an aliased mutable reference, which would
200 violate the *second* rule of references.
201
202 However this is *not at all* how Rust reasons that this program is bad. Rust
203 doesn't understand that `x` is a reference to a subpath of `data`. It doesn't
204 understand Vec at all. What it *does* see is that `x` has to live for `'b` to
205 be printed. The signature of `Index::index` subsequently demands that the
206 reference we take to *data* has to survive for `'b`. When we try to call `push`,
207 it then sees us try to make an `&'c mut data`. Rust knows that `'c` is contained
208 within `'b`, and rejects our program because the `&'b data` must still be live!
209
210 Here we see that the lifetime system is *much* more coarse than the reference
211 semantics we're actually interested in preserving. For the most part, *that's
212 totally ok*, because it keeps us from spending all day explaining our program
213 to the compiler. However it does mean that several programs that are *totally*
214 correct with respect to Rust's *true* semantics are rejected because lifetimes
215 are too dumb.