]> git.proxmox.com Git - rustc.git/blob - src/doc/book/second-edition/src/ch19-02-advanced-lifetimes.md
New upstream version 1.25.0+dfsg1
[rustc.git] / src / doc / book / second-edition / src / ch19-02-advanced-lifetimes.md
1 ## Advanced Lifetimes
2
3 Back in Chapter 10 in the “Validating References with Lifetimes” section, we
4 learned how to annotate references with lifetime parameters to tell Rust how
5 lifetimes of different references relate. We saw how every reference has a
6 lifetime but, most of the time, Rust will let you elide lifetimes. Here we’ll
7 look at three advanced features of lifetimes that we haven’t covered yet:
8
9 * Lifetime subtyping, a way to ensure that one lifetime outlives another
10 lifetime
11 * Lifetime bounds, to specify a lifetime for a reference to a generic type
12 * Trait object lifetimes, how they’re inferred, and when they need to be
13 specified
14
15 <!-- maybe add a small summary of each here? That would let us launch straight
16 into examples in the next section -->
17 <!-- I've switched to bullets and added a small summary /Carol -->
18
19 ### Lifetime Subtyping Ensures One Lifetime Outlives Another
20
21 Lifetime subtyping is a way to specify that one lifetime should outlive another
22 lifetime. To explore lifetime subtyping, imagine we want to write a parser.
23 We’ll have a structure called `Context` that holds a reference to the string
24 we’re parsing. We’ll write a parser that will parse this string and return
25 success or failure. The parser will need to borrow the context to do the
26 parsing. Implementing this would look like the code in Listing 19-12, except
27 this code doesn’t have the required lifetime annotations so it won’t compile:
28
29 <span class="filename">Filename: src/lib.rs</span>
30
31 ```rust,ignore
32 struct Context(&str);
33
34 struct Parser {
35 context: &Context,
36 }
37
38 impl Parser {
39 fn parse(&self) -> Result<(), &str> {
40 Err(&self.context.0[1..])
41 }
42 }
43 ```
44
45 <span class="caption">Listing 19-12: Defining a parser without lifetime
46 annotations</span>
47
48 Compiling the code results in errors saying that Rust expected lifetime
49 parameters on the string slice in `Context` and the reference to a `Context` in
50 `Parser`.
51
52 <!-- What will the compile time error be here? I think it'd be worth showing
53 that to the reader -->
54 <!-- The errors just say "expected lifetime parameter", they're pretty boring.
55 We've shown error messages like that before so I've explained in words instead.
56 /Carol -->
57
58 For simplicity’s sake, our `parse` function returns a `Result<(), &str>`. That
59 is, it will do nothing on success, and on failure will return the part of the
60 string slice that didn’t parse correctly. A real implementation would have more
61 error information than that, and would actually return something when parsing
62 succeeds, but we’ll leave those off because they aren’t relevant to the
63 lifetimes part of this example.
64
65 To keep this code simple, we’re not going to actually write any parsing logic.
66 It’s very likely that somewhere in parsing logic we’d handle invalid input by
67 returning an error that references the part of the input that’s invalid, and
68 this reference is what makes the code example interesting with regards to
69 lifetimes. So we’re going to pretend that the logic of our parser is that the
70 input is invalid after the first byte. Note that this code may panic if the
71 first byte is not on a valid character boundary; again, we’re simplifying the
72 example in order to concentrate on the lifetimes involved.
73
74 <!-- why do we want to always error after the first byte? -->
75 <!-- For simplicity of the example to avoid cluttering up the code with actual
76 parsing logic, which isn't the point. I've explained a bit more above /Carol -->
77
78 To get this code compiling, we need to fill in the lifetime parameters for the
79 string slice in `Context` and the reference to the `Context` in `Parser`. The
80 most straightforward way to do this is to use the same lifetime everywhere, as
81 shown in Listing 19-13:
82
83 <span class="filename">Filename: src/lib.rs</span>
84
85 ```rust
86 struct Context<'a>(&'a str);
87
88 struct Parser<'a> {
89 context: &'a Context<'a>,
90 }
91
92 impl<'a> Parser<'a> {
93 fn parse(&self) -> Result<(), &str> {
94 Err(&self.context.0[1..])
95 }
96 }
97 ```
98
99 <span class="caption">Listing 19-13: Annotating all references in `Context` and
100 `Parser` with the same lifetime parameter</span>
101
102 This compiles fine, and tells Rust that a `Parser` holds a reference to a
103 `Context` with lifetime `'a`, and that `Context` holds a string slice that also
104 lives as long as the reference to the `Context` in `Parser`. Rust’s compiler
105 error message said lifetime parameters were required for these references, and
106 we have now added lifetime parameters.
107
108 <!-- can you let the reader know they should be taking away from this previous
109 example? I'm not totally clear on why adding lifetimes here saved the code -->
110 <!-- Done -->
111
112 Next, in Listing 19-14, let’s add a function that takes an instance of
113 `Context`, uses a `Parser` to parse that context, and returns what `parse`
114 returns. This won’t quite work:
115
116 <span class="filename">Filename: src/lib.rs</span>
117
118 ```rust,ignore
119 fn parse_context(context: Context) -> Result<(), &str> {
120 Parser { context: &context }.parse()
121 }
122 ```
123
124 <span class="caption">Listing 19-14: An attempt to add a `parse_context`
125 function that takes a `Context` and uses a `Parser`</span>
126
127 We get two quite verbose errors when we try to compile the code with the
128 addition of the `parse_context` function:
129
130 ```text
131 error[E0597]: borrowed value does not live long enough
132 --> src/lib.rs:14:5
133 |
134 14 | Parser { context: &context }.parse()
135 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
136 15 | }
137 | - temporary value only lives until here
138 |
139 note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 13:1...
140 --> src/lib.rs:13:1
141 |
142 13 | / fn parse_context(context: Context) -> Result<(), &str> {
143 14 | | Parser { context: &context }.parse()
144 15 | | }
145 | |_^
146
147 error[E0597]: `context` does not live long enough
148 --> src/lib.rs:14:24
149 |
150 14 | Parser { context: &context }.parse()
151 | ^^^^^^^ does not live long enough
152 15 | }
153 | - borrowed value only lives until here
154 |
155 note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 13:1...
156 --> src/lib.rs:13:1
157 |
158 13 | / fn parse_context(context: Context) -> Result<(), &str> {
159 14 | | Parser { context: &context }.parse()
160 15 | | }
161 | |_^
162 ```
163
164 These errors are saying that both the `Parser` instance that’s created and the
165 `context` parameter live only from when the `Parser` is created until the end
166 of the `parse_context` function, but they both need to live for the entire
167 lifetime of the function.
168
169 In other words, `Parser` and `context` need to *outlive* the entire function
170 and be valid before the function starts as well as after it ends in order for
171 all the references in this code to always be valid. Both the `Parser` we’re
172 creating and the `context` parameter go out of scope at the end of the
173 function, though (because `parse_context` takes ownership of `context`).
174
175 <!-- Oh interesting, why do they need to outlive the function, simply to
176 absolutely ensure they will live for as long as the function? -->
177 <!-- Yes, which is what I think we've said in the first sentence of the
178 previous paragraph. Is there something that's unclear? /Carol -->
179
180 To figure out why we’re getting these errors, let’s look at the definitions in
181 Listing 19-13 again, specifically the references in the signature of the
182 `parse` method:
183
184 ```rust,ignore
185 fn parse(&self) -> Result<(), &str> {
186 ```
187
188 <!-- What exactly is it the reader should be looking at in this signature? -->
189 <!-- Added above /Carol -->
190
191 Remember the elision rules? If we annotate the lifetimes of the references
192 rather than eliding, the signature would be:
193
194 ```rust,ignore
195 fn parse<'a>(&'a self) -> Result<(), &'a str> {
196 ```
197
198 That is, the error part of the return value of `parse` has a lifetime that is
199 tied to the lifetime of the `Parser` instance (that of `&self` in the `parse`
200 method signature). That makes sense: the returned string slice references the
201 string slice in the `Context` instance held by the `Parser`, and the definition
202 of the `Parser` struct specifies that the lifetime of the reference to
203 `Context` and the lifetime of the string slice that `Context` holds should be
204 the same.
205
206 The problem is that the `parse_context` function returns the value returned
207 from `parse`, so the lifetime of the return value of `parse_context` is tied to
208 the lifetime of the `Parser` as well. But the `Parser` instance created in the
209 `parse_context` function won’t live past the end of the function (it’s
210 temporary), and `context` will go out of scope at the end of the function
211 (`parse_context` takes ownership of it).
212
213 Rust thinks we’re trying to return a reference to a value that goes out of
214 scope at the end of the function, because we annotated all the lifetimes with
215 the same lifetime parameter. That told Rust the lifetime of the string slice
216 that `Context` holds is the same as that of the lifetime of the reference to
217 `Context` that `Parser` holds.
218
219 The `parse_context` function can’t see that within the `parse` function, the
220 string slice returned will outlive both `Context` and `Parser`, and that the
221 reference `parse_context` returns refers to the string slice, not to `Context`
222 or `Parser`.
223
224 By knowing what the implementation of `parse` does, we know that the only
225 reason the return value of `parse` is tied to the `Parser` is because it’s
226 referencing the `Parser`’s `Context`, which is referencing the string slice, so
227 it’s really the lifetime of the string slice that `parse_context` needs to care
228 about. We need a way to tell Rust that the string slice in `Context` and the
229 reference to the `Context` in `Parser` have different lifetimes and that the
230 return value of `parse_context` is tied to the lifetime of the string slice in
231 `Context`.
232
233 First we’ll try giving `Parser` and `Context` different lifetime parameters as
234 shown in Listing 19-15. We’ll use `'s` and `'c` as lifetime parameter names to
235 be clear about which lifetime goes with the string slice in `Context` and which
236 goes with the reference to `Context` in `Parser`. Note that this won’t
237 completely fix the problem, but it’s a start and we’ll look at why this isn’t
238 sufficient when we try to compile.
239
240 <span class="filename">Filename: src/lib.rs</span>
241
242 ```rust,ignore
243 struct Context<'s>(&'s str);
244
245 struct Parser<'c, 's> {
246 context: &'c Context<'s>,
247 }
248
249 impl<'c, 's> Parser<'c, 's> {
250 fn parse(&self) -> Result<(), &'s str> {
251 Err(&self.context.0[1..])
252 }
253 }
254
255 fn parse_context(context: Context) -> Result<(), &str> {
256 Parser { context: &context }.parse()
257 }
258 ```
259
260 <span class="caption">Listing 19-15: Specifying different lifetime parameters
261 for the references to the string slice and to `Context`</span>
262
263 We’ve annotated the lifetimes of the references in all the same places that we
264 annotated them in Listing 19-13, but used different parameters depending on
265 whether the reference goes with the string slice or with `Context`. We’ve also
266 added an annotation to the string slice part of the return value of `parse` to
267 indicate that it goes with the lifetime of the string slice in `Context`.
268
269 The following is the error we get now when we try to compile:
270
271 ```text
272 error[E0491]: in type `&'c Context<'s>`, reference has a longer lifetime than the data it references
273 --> src/lib.rs:4:5
274 |
275 4 | context: &'c Context<'s>,
276 | ^^^^^^^^^^^^^^^^^^^^^^^^
277 |
278 note: the pointer is valid for the lifetime 'c as defined on the struct at 3:1
279 --> src/lib.rs:3:1
280 |
281 3 | / struct Parser<'c, 's> {
282 4 | | context: &'c Context<'s>,
283 5 | | }
284 | |_^
285 note: but the referenced data is only valid for the lifetime 's as defined on the struct at 3:1
286 --> src/lib.rs:3:1
287 |
288 3 | / struct Parser<'c, 's> {
289 4 | | context: &'c Context<'s>,
290 5 | | }
291 | |_^
292 ```
293
294 Rust doesn’t know of any relationship between `'c` and `'s`. In order to be
295 valid, the referenced data in `Context` with lifetime `'s` needs to be
296 constrained, to guarantee that it lives longer than the reference with lifetime
297 `'c`. If `'s` is not longer than `'c`, the reference to `Context` might not be
298 valid.
299
300 Which gets us to the point of this section: the Rust feature *lifetime
301 subtyping* is a way to specify that one lifetime parameter lives at least as
302 long as another one. In the angle brackets where we declare lifetime
303 parameters, we can declare a lifetime `'a` as usual, and declare a lifetime
304 `'b` that lives at least as long as `'a` by declaring `'b` with the syntax `'b:
305 'a`.
306
307 In our definition of `Parser`, in order to say that `'s` (the lifetime of the
308 string slice) is guaranteed to live at least as long as `'c` (the lifetime of
309 the reference to `Context`), we change the lifetime declarations to look like
310 this:
311
312 <span class="filename">Filename: src/lib.rs</span>
313
314 ```rust
315 # struct Context<'a>(&'a str);
316 #
317 struct Parser<'c, 's: 'c> {
318 context: &'c Context<'s>,
319 }
320 ```
321
322 Now, the reference to `Context` in the `Parser` and the reference to the string
323 slice in the `Context` have different lifetimes, and we’ve ensured that the
324 lifetime of the string slice is longer than the reference to the `Context`.
325
326 That was a very long-winded example, but as we mentioned at the start of this
327 chapter, these features are pretty niche. You won’t often need this syntax, but
328 it can come up in situations like this one, where you need to refer to
329 something you have a reference to.
330
331 ### Lifetime Bounds on References to Generic Types
332
333 In the “Trait Bounds” section of Chapter 10, we discussed using trait bounds on
334 generic types. We can also add lifetime parameters as constraints on generic
335 types, and these are called *lifetime bounds*. Lifetime bounds help Rust verify
336 that references in generic types won’t outlive the data they’re referencing.
337
338 <!-- Can you say up front why/when we use these? -->
339 <!-- Done -->
340
341 For an example, consider a type that is a wrapper over references. Recall the
342 `RefCell<T>` type from the “`RefCell<T>` and the Interior Mutability Pattern”
343 section of Chapter 15: its `borrow` and `borrow_mut` methods return the types
344 `Ref` and `RefMut`, respectively. These types are wrappers over references that
345 keep track of the borrowing rules at runtime. The definition of the `Ref`
346 struct is shown in Listing 19-16, without lifetime bounds for now:
347
348 <span class="filename">Filename: src/lib.rs</span>
349
350 ```rust,ignore
351 struct Ref<'a, T>(&'a T);
352 ```
353
354 <span class="caption">Listing 19-16: Defining a struct to wrap a reference to a
355 generic type; without lifetime bounds to start</span>
356
357 Without explicitly constraining the lifetime `'a` in relation to the generic
358 parameter `T`, Rust will error because it doesn’t know how long the generic
359 type `T` will live:
360
361 ```text
362 error[E0309]: the parameter type `T` may not live long enough
363 --> src/lib.rs:1:19
364 |
365 1 | struct Ref<'a, T>(&'a T);
366 | ^^^^^^
367 |
368 = help: consider adding an explicit lifetime bound `T: 'a`...
369 note: ...so that the reference type `&'a T` does not outlive the data it points at
370 --> src/lib.rs:1:19
371 |
372 1 | struct Ref<'a, T>(&'a T);
373 | ^^^^^^
374 ```
375
376 Because `T` can be any type, `T` could itself be a reference or a type that
377 holds one or more references, each of which could have their own lifetimes.
378 Rust can’t be sure `T` will live as long as `'a`.
379
380 Fortunately, that error gave us helpful advice on how to specify the lifetime
381 bound in this case:
382
383 ```text
384 consider adding an explicit lifetime bound `T: 'a` so that the reference type
385 `&'a T` does not outlive the data it points at
386 ```
387
388 Listing 19-17 shows how to apply this advice by specifying the lifetime bound
389 when we declare the generic type `T`.
390
391 ```rust
392 struct Ref<'a, T: 'a>(&'a T);
393 ```
394
395 <span class="caption">Listing 19-17: Adding lifetime bounds on `T` to specify
396 that any references in `T` live at least as long as `'a`</span>
397
398 This code now compiles because the `T: 'a` syntax specifies that `T` can be any
399 type, but if it contains any references, the references must live at least as
400 long as `'a`.
401
402 We could solve this in a different way, shown in the definition of a
403 `StaticRef` struct in Listing 19-18, by adding the `'static` lifetime bound on
404 `T`. This means if `T` contains any references, they must have the `'static`
405 lifetime:
406
407 ```rust
408 struct StaticRef<T: 'static>(&'static T);
409 ```
410
411 <span class="caption">Listing 19-18: Adding a `'static` lifetime bound to `T`
412 to constrain `T` to types that have only `'static` references or no
413 references</span>
414
415 Because `'static` means the reference must live as long as the entire program,
416 a type that contains no references meets the criteria of all references living
417 as long as the entire program (because there are no references). For the borrow
418 checker concerned about references living long enough, there’s no real
419 distinction between a type that has no references and a type that has
420 references that live forever; both of them are the same for the purpose of
421 determining whether or not a reference has a shorter lifetime than what it
422 refers to.
423
424 ### Inference of Trait Object Lifetimes
425
426 In Chapter 17 in the “Using Trait Objects that Allow for Values of Different
427 Types” section, we discussed trait objects, consisting of a trait behind a
428 reference, that allow us to use dynamic dispatch. We haven’t yet discussed what
429 happens if the type implementing the trait in the trait object has a lifetime
430 of its own. Consider Listing 19-19, where we have a trait `Red` and a struct
431 `Ball`. `Ball` holds a reference (and thus has a lifetime parameter) and also
432 implements trait `Red`. We want to use an instance of `Ball` as the trait
433 object `Box<Red>`:
434
435 <span class="filename">Filename: src/main.rs</span>
436
437 ```rust
438 trait Red { }
439
440 struct Ball<'a> {
441 diameter: &'a i32,
442 }
443
444 impl<'a> Red for Ball<'a> { }
445
446 fn main() {
447 let num = 5;
448
449 let obj = Box::new(Ball { diameter: &num }) as Box<Red>;
450 }
451 ```
452
453 <span class="caption">Listing 19-19: Using a type that has a lifetime parameter
454 with a trait object</span>
455
456 This code compiles without any errors, even though we haven’t said anything
457 explicit about the lifetimes involved in `obj`. This works because there are
458 rules having to do with lifetimes and trait objects:
459
460 * The default lifetime of a trait object is `'static`.
461 * With `&'a Trait` or `&'a mut Trait`, the default lifetime is `'a`.
462 * With a single `T: 'a` clause, the default lifetime is `'a`.
463 * With multiple `T: 'a`-like clauses, there is no default; we must
464 be explicit.
465
466 When we must be explicit, we can add a lifetime bound on a trait object like
467 `Box<Red>` with the syntax `Box<Red + 'a>` or `Box<Red + 'static>`, depending
468 on what’s needed. Just as with the other bounds, this means that any
469 implementor of the `Red` trait that has references inside must have the
470 same lifetime specified in the trait object bounds as those references.
471
472 Next, let’s take a look at some other advanced features dealing with traits!