]> git.proxmox.com Git - rustc.git/blob - src/doc/book/second-edition/src/ch19-02-advanced-lifetimes.md
New upstream version 1.20.0+dfsg1
[rustc.git] / src / doc / book / second-edition / src / ch19-02-advanced-lifetimes.md
1 ## Advanced Lifetimes
2
3 Back in Chapter 10, we learned how to annotate references with lifetime
4 parameters to help Rust understand how the lifetimes of different references
5 relate. We saw how most of the time, Rust will let you elide lifetimes, but
6 every reference has a lifetime. There are three advanced features of lifetimes
7 that we haven't covered though: *lifetime subtyping*, *lifetime
8 bounds*, and *trait object lifetimes*.
9
10 ### Lifetime Subtyping
11
12 Imagine that we want to write a parser. To do this, we'll have a structure that
13 holds a reference to the string that we're parsing, and we'll call that struct
14 `Context`. We'll write a parser that will parse this string and return success
15 or failure. The parser will need to borrow the context to do the parsing.
16 Implementing this would look like the code in Listing 19-12, which won't
17 compile because we've left off the lifetime annotations for now:
18
19 ```rust,ignore
20 struct Context(&str);
21
22 struct Parser {
23 context: &Context,
24 }
25
26 impl Parser {
27 fn parse(&self) -> Result<(), &str> {
28 Err(&self.context.0[1..])
29 }
30 }
31 ```
32
33 <span class="caption">Listing 19-12: Defining a `Context` struct that holds a
34 string slice, a `Parser` struct that holds a reference to a `Context` instance,
35 and a `parse` method that always returns an error referencing the string
36 slice</span>
37
38 For simplicity's sake, our `parse` function returns a `Result<(), &str>`. That
39 is, we don't do anything on success, and on failure we return the part of the
40 string slice that didn't parse correctly. A real implementation would have more
41 error information than that, and would actually return something created when
42 parsing succeeds, but we're leaving those parts of the implementation off since
43 they aren't relevant to the lifetimes part of this example. We're also defining
44 `parse` to always produce an error after the first byte. Note that this may
45 panic if the first byte is not on a valid character boundary; again, we're
46 simplifying the example in order to concentrate on the lifetimes involved.
47
48 So how do we fill in the lifetime parameters for the string slice in `Context`
49 and the reference to the `Context` in `Parser`? The most straightforward thing
50 to do is to use the same lifetime everywhere, as shown in Listing 19-13:
51
52 ```rust
53 struct Context<'a>(&'a str);
54
55 struct Parser<'a> {
56 context: &'a Context<'a>,
57 }
58
59 impl<'a> Parser<'a> {
60 fn parse(&self) -> Result<(), &str> {
61 Err(&self.context.0[1..])
62 }
63 }
64 ```
65
66 <span class="caption">Listing 19-13: Annotating all references in `Context` and
67 `Parser` with the same lifetime parameter</span>
68
69 This compiles fine. Next, in Listing 19-14, let's write a function that takes
70 an instance of `Context`, uses a `Parser` to parse that context, and returns
71 what `parse` returns. This won't quite work:
72
73 ```rust,ignore
74 fn parse_context(context: Context) -> Result<(), &str> {
75 Parser { context: &context }.parse()
76 }
77 ```
78
79 <span class="caption">Listing 19-14: An attempt to add a `parse_context`
80 function that takes a `Context` and uses a `Parser`</span>
81
82 We get two quite verbose errors when we try to compile the code with the
83 addition of the `parse_context` function:
84
85 ```text
86 error: borrowed value does not live long enough
87 --> <anon>:16:5
88 |
89 16 | Parser { context: &context }.parse()
90 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
91 17 | }
92 | - temporary value only lives until here
93 |
94 note: borrowed value must be valid for the anonymous lifetime #1 defined on the
95 body at 15:55...
96 --> <anon>:15:56
97 |
98 15 | fn parse_context(context: Context) -> Result<(), &str> {
99 | ________________________________________________________^
100 16 | | Parser { context: &context }.parse()
101 17 | | }
102 | |_^
103
104 error: `context` does not live long enough
105 --> <anon>:16:24
106 |
107 16 | Parser { context: &context }.parse()
108 | ^^^^^^^ does not live long enough
109 17 | }
110 | - borrowed value only lives until here
111 |
112 note: borrowed value must be valid for the anonymous lifetime #1 defined on the
113 body at 15:55...
114 --> <anon>:15:56
115 |
116 15 | fn parse_context(context: Context) -> Result<(), &str> {
117 | ________________________________________________________^
118 16 | | Parser { context: &context }.parse()
119 17 | | }
120 | |_^
121 ```
122
123 These errors are saying that both the `Parser` instance we're creating and the
124 `context` parameter live from the line that the `Parser` is created until the
125 end of the `parse_context` function, but they both need to live for the entire
126 lifetime of the function.
127
128 In other words, `Parser` and `context` need to *outlive* the entire function
129 and be valid before the function starts as well as after it ends in order for
130 all the references in this code to always be valid. Both the `Parser` we're
131 creating and the `context` parameter go out of scope at the end of the
132 function, though (since `parse_context` takes ownership of `context`).
133
134 Let's look at the definitions in Listing 19-13 again, especially the signature
135 of the `parse` method:
136
137 ```rust,ignore
138 fn parse(&self) -> Result<(), &str> {
139 ```
140
141 Remember the elision rules? If we annotate the lifetimes of the references, the
142 signature would be:
143
144 ```rust,ignore
145 fn parse<'a>(&'a self) -> Result<(), &'a str> {
146 ```
147
148 That is, the error part of the return value of `parse` has a lifetime that is
149 tied to the `Parser` instance's lifetime (that of `&self` in the `parse` method
150 signature). That makes sense, as the returned string slice references the
151 string slice in the `Context` instance that the `Parser` holds, and we've
152 specified in the definition of the `Parser` struct that the lifetime of the
153 reference to `Context` that `Parser` holds and the lifetime of the string slice
154 that `Context` holds should be the same.
155
156 The problem is that the `parse_context` function returns the value returned
157 from `parse`, so the lifetime of the return value of `parse_context` is tied to
158 the lifetime of the `Parser` as well. But the `Parser` instance created in the
159 `parse_context` function won't live past the end of the function (it's
160 temporary), and the `context` will go out of scope at the end of the function
161 (`parse_context` takes ownership of it).
162
163 We're not allowed to return a reference to a value that goes out of scope at
164 the end of the function. Rust thinks that's what we're trying to do because we
165 annotated all the lifetimes with the same lifetime parameter. That told Rust
166 the lifetime of the string slice that `Context` holds is the same as that of
167 the lifetime of the reference to `Context` that `Parser` holds.
168
169 The `parse_context` function can't see that within the `parse` function, the
170 string slice returned will outlive both `Context` and `Parser`, and that the
171 reference `parse_context` returns refers to the string slice, not to `Context`
172 or `Parser`.
173
174 By knowing what the implementation of `parse` does, we know that the only
175 reason that the return value of `parse` is tied to the `Parser` is because it's
176 referencing the `Parser`'s `Context`, which is referencing the string slice, so
177 it's really the lifetime of the string slice that `parse_context` needs to care
178 about. We need a way to tell Rust that the string slice in `Context` and the
179 reference to the `Context` in `Parser` have different lifetimes and that the
180 return value of `parse_context` is tied to the lifetime of the string slice in
181 `Context`.
182
183 We could try only giving `Parser` and `Context` different lifetime parameters
184 as shown in Listing 19-15. We've chosen the lifetime parameter names `'s` and
185 `'c` here to be clearer about which lifetime goes with the string slice in
186 `Context` and which goes with the reference to `Context` in `Parser`. Note that
187 this won't completely fix the problem, but it's a start and we'll look at why
188 this isn't sufficient when we try to compile.
189
190 ```rust,ignore
191 struct Context<'s>(&'s str);
192
193 struct Parser<'c, 's> {
194 context: &'c Context<'s>,
195 }
196
197 impl<'c, 's> Parser<'c, 's> {
198 fn parse(&self) -> Result<(), &'s str> {
199 Err(&self.context.0[1..])
200 }
201 }
202
203 fn parse_context(context: Context) -> Result<(), &str> {
204 Parser { context: &context }.parse()
205 }
206 ```
207
208 <span class="caption">Listing 19-15: Specifying different lifetime parameters
209 for the references to the string slice and to `Context`</span>
210
211 We've annotated the lifetimes of the references in all the same places that we
212 annotated them in Listing 19-13, but used different parameters depending on
213 whether the reference goes with the string slice or with `Context`. We've also
214 added an annotation to the string slice part of the return value of `parse` to
215 indicate that it goes with the lifetime of the string slice in `Context`.
216
217 Here's the error we get now:
218
219 ```text
220 error[E0491]: in type `&'c Context<'s>`, reference has a longer lifetime than the data it references
221 --> src/main.rs:4:5
222 |
223 4 | context: &'c Context<'s>,
224 | ^^^^^^^^^^^^^^^^^^^^^^^^
225 |
226 note: the pointer is valid for the lifetime 'c as defined on the struct at 3:0
227 --> src/main.rs:3:1
228 |
229 3 | / struct Parser<'c, 's> {
230 4 | | context: &'c Context<'s>,
231 5 | | }
232 | |_^
233 note: but the referenced data is only valid for the lifetime 's as defined on the struct at 3:0
234 --> src/main.rs:3:1
235 |
236 3 | / struct Parser<'c, 's> {
237 4 | | context: &'c Context<'s>,
238 5 | | }
239 | |_^
240 ```
241
242 Rust doesn't know of any relationship between `'c` and `'s`. In order to be
243 valid, the referenced data in `Context` with lifetime `'s` needs to be
244 constrained to guarantee that it lives longer than the reference to `Context`
245 that has lifetime `'c`. If `'s` is not longer than `'c`, then the reference to
246 `Context` might not be valid.
247
248 Which gets us to the point of this section: Rust has a feature called *lifetime
249 subtyping*, which is a way to specify that one lifetime parameter lives at
250 least as long as another one. In the angle brackets where we declare lifetime
251 parameters, we can declare a lifetime `'a` as usual, and declare a lifetime
252 `'b` that lives at least as long as `'a` by declaring `'b` with the syntax `'b:
253 'a`.
254
255 In our definition of `Parser`, in order to say that `'s` (the lifetime of the
256 string slice) is guaranteed to live at least as long as `'c` (the lifetime of
257 the reference to `Context`), we change the lifetime declarations to look like
258 this:
259
260 ```rust
261 # struct Context<'a>(&'a str);
262 #
263 struct Parser<'c, 's: 'c> {
264 context: &'c Context<'s>,
265 }
266 ```
267
268 Now, the reference to `Context` in the `Parser` and the reference to the string
269 slice in the `Context` have different lifetimes, and we've ensured that the
270 lifetime of the string slice is longer than the reference to the `Context`.
271
272 That was a very long-winded example, but as we mentioned at the start of this
273 chapter, these features are pretty niche. You won't often need this syntax, but
274 it can come up in situations like this one, where you need to refer to
275 something you have a reference to.
276
277 ### Lifetime Bounds
278
279 In Chapter 10, we discussed how to use trait bounds on generic types. We can
280 also add lifetime parameters as constraints on generic types, which are called
281 *lifetime bounds*. For example, consider a type that is a wrapper over
282 references. Recall the `RefCell<T>` type from Chapter 15: its `borrow` and
283 `borrow_mut` methods return the types `Ref` and `RefMut`, respectively. These
284 types are wrappers over references that keep track of the borrowing rules at
285 runtime. The definition of the `Ref` struct is shown in Listing 19-16, without
286 lifetime bounds for now:
287
288 ```rust,ignore
289 struct Ref<'a, T>(&'a T);
290 ```
291
292 <span class="caption">Listing 19-16: Defining a struct to wrap a reference to a
293 generic type; without lifetime bounds to start</span>
294
295 Without constraining the lifetime `'a` in relation to the generic parameter
296 `T`, we get an error because Rust doesn't know how long the generic type `T`
297 will live:
298
299 ```text
300 error[E0309]: the parameter type `T` may not live long enough
301 --> <anon>:1:19
302 |
303 1 | struct Ref<'a, T>(&'a T);
304 | ^^^^^^
305 |
306 = help: consider adding an explicit lifetime bound `T: 'a`...
307 note: ...so that the reference type `&'a T` does not outlive the data it points at
308 --> <anon>:1:19
309 |
310 1 | struct Ref<'a, T>(&'a T);
311 | ^^^^^^
312 ```
313
314 Since `T` can be any type, `T` could itself be a reference or a type that holds
315 one or more references, each of which could have their own lifetimes. Rust
316 can't be sure `T` will live as long as `'a`.
317
318 Fortunately, Rust gave us helpful advice on how to specify the lifetime bound in
319 this case:
320
321 ```text
322 consider adding an explicit lifetime bound `T: 'a` so that the reference type
323 `&'a T` does not outlive the data it points at.
324 ```
325
326 Listing 19-17 shows how to apply this advice by specifying the lifetime bound
327 when we declare the generic type `T`. This code now compiles because the `T:
328 'a` syntax specifies that `T` can be any type, but if it contains any
329 references, the references must live at least as long as `'a`:
330
331 ```rust
332 struct Ref<'a, T: 'a>(&'a T);
333 ```
334
335 <span class="caption">Listing 19-17: Adding lifetime bounds on `T` to specify
336 that any references in `T` live at least as long as `'a`</span>
337
338 We could choose to solve this in a different way, shown in the definition of a
339 `StaticRef` struct in Listing 19-18, by adding the `'static` lifetime bound on
340 `T`. This means if `T` contains any references, they must have the `'static`
341 lifetime:
342
343 ```rust
344 struct StaticRef<T: 'static>(&'static T);
345 ```
346
347 <span class="caption">Listing 19-18: Adding a `'static` lifetime bound to `T`
348 to constrain `T` to types that have only `'static` references or no
349 references</span>
350
351 Types without any references count as `T: 'static`. Because `'static` means the
352 reference must live as long as the entire program, a type that contains no
353 references meets the criteria of all references living as long as the entire
354 program (since there are no references). Think of it this way: if the borrow
355 checker is concerned about references living long enough, then there's no real
356 distinction between a type that has no references and a type that has
357 references that live forever; both of them are the same for the purpose of
358 determining whether or not a reference has a shorter lifetime than what it
359 refers to.
360
361 ### Trait Object Lifetimes
362
363 In Chapter 17, we learned about trait objects that consist of putting a trait
364 behind a reference in order to use dynamic dispatch. However, we didn't discuss
365 what happens if the type implementing the trait used in the trait object has a
366 lifetime. Consider Listing 19-19, where we have a trait `Foo` and a struct
367 `Bar` that holds a reference (and thus has a lifetime parameter) that
368 implements trait `Foo`, and we want to use an instance of `Bar` as the trait
369 object `Box<Foo>`:
370
371 ```rust
372 trait Foo { }
373
374 struct Bar<'a> {
375 x: &'a i32,
376 }
377
378 impl<'a> Foo for Bar<'a> { }
379
380 let num = 5;
381
382 let obj = Box::new(Bar { x: &num }) as Box<Foo>;
383 ```
384
385 <span class="caption">Listing 19-19: Using a type that has a lifetime parameter
386 with a trait object</span>
387
388 This code compiles without any errors, even though we haven't said anything
389 about the lifetimes involved in `obj`. This works because there are rules
390 having to do with lifetimes and trait objects:
391
392 * The default lifetime of a trait object is `'static`.
393 * If we have `&'a X` or `&'a mut X`, then the default is `'a`.
394 * If we have a single `T: 'a` clause, then the default is `'a`.
395 * If we have multiple `T: 'a`-like clauses, then there is no default; we must
396 be explicit.
397
398 When we must be explicit, we can add a lifetime bound on a trait object like
399 `Box<Foo>` with the syntax `Box<Foo + 'a>` or `Box<Foo + 'static>`, depending
400 on what's needed. Just as with the other bounds, this means that any
401 implementer of the `Foo` trait that has any references inside must have the
402 lifetime specified in the trait object bounds as those references.
403
404 Next, let's take a look at some other advanced features dealing with traits!