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