]> git.proxmox.com Git - rustc.git/blame - src/doc/book/nostarch/chapter10.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / book / nostarch / chapter10.md
CommitLineData
5099ac24
FG
1<!-- DO NOT EDIT THIS FILE.
2
3This file is periodically generated from the content in the `/src/`
4directory, so all fixes need to be made in `/src/`.
5-->
3c0e092e
XL
6
7[TOC]
8
9# Generic Types, Traits, and Lifetimes
10
11Every programming language has tools for effectively handling the duplication
5e7ed085
FG
12of concepts. In Rust, one such tool is *generics*: abstract stand-ins for
13concrete types or other properties. We can express the behavior of generics or
14how they relate to other generics without knowing what will be in their place
15when compiling and running the code.
16
17Functions can take parameters of some generic type, instead of a concrete type
18like `i32` or `String`, in the same way a function takes parameters with
19unknown values to run the same code on multiple concrete values. In fact, we’ve
3c0e092e
XL
20already used generics in Chapter 6 with `Option<T>`, Chapter 8 with `Vec<T>`
21and `HashMap<K, V>`, and Chapter 9 with `Result<T, E>`. In this chapter, you’ll
22explore how to define your own types, functions, and methods with generics!
23
5e7ed085
FG
24First, we’ll review how to extract a function to reduce code duplication. We’ll
25then use the same technique to make a generic function from two functions that
3c0e092e
XL
26differ only in the types of their parameters. We’ll also explain how to use
27generic types in struct and enum definitions.
28
29Then you’ll learn how to use *traits* to define behavior in a generic way. You
5e7ed085
FG
30can combine traits with generic types to constrain a generic type to accept
31only those types that have a particular behavior, as opposed to just any type.
3c0e092e 32
5e7ed085 33Finally, we’ll discuss *lifetimes*: a variety of generics that give the
3c0e092e 34compiler information about how references relate to each other. Lifetimes allow
5e7ed085
FG
35us to give the compiler enough information about borrowed values so that it can
36ensure references will be valid in more situations than it could without our
37help.
3c0e092e
XL
38
39## Removing Duplication by Extracting a Function
40
5e7ed085
FG
41Generics allow us to replace specific types with a placeholder that represents
42multiple types to remove code duplication.
5e7ed085
FG
43Before diving into generics syntax, then, let’s first look at how to remove
44duplication in a way that doesn’t involve generic types by extracting a
45function that replaces specific values with a placeholder that represents
46multiple values. Then we’ll apply the same technique to extract a generic
47function! By looking at how to recognize duplicated code you can extract into a
48function, you’ll start to recognize duplicated code that can use generics.
49
50We begin with the short program in Listing 10-1 that finds the largest number
51in a list.
3c0e092e
XL
52
53Filename: src/main.rs
54
55```
56fn main() {
57 let number_list = vec![34, 50, 25, 100, 65];
58
923072b8 59 let mut largest = &number_list[0];
3c0e092e 60
923072b8 61 for number in &number_list {
3c0e092e
XL
62 if number > largest {
63 largest = number;
64 }
65 }
66
67 println!("The largest number is {}", largest);
68}
69```
70
5e7ed085 71Listing 10-1: Finding the largest number in a list of numbers
3c0e092e 72
923072b8
FG
73We store a list of integers in the variable `number_list` and place a reference
74to the first number in the list in a variable named `largest`. We then iterate
75through all the numbers in the list, and if the current number is greater than
76the number stored in `largest`, replace the reference in that variable.
77However, if the current number is less than or equal to the largest number seen
78so far, the variable doesn’t change, and the code moves on to the next number
79in the list. After considering all the numbers in the list, `largest` should
80refer to the largest number, which in this case is 100.
3c0e092e 81
5e7ed085
FG
82We've now been tasked with finding the largest number in two different lists of
83numbers. To do so, we can choose to duplicate the code in Listing 10-1 and use
84the same logic at two different places in the program, as shown in Listing 10-2.
3c0e092e
XL
85
86Filename: src/main.rs
87
88```
89fn main() {
90 let number_list = vec![34, 50, 25, 100, 65];
91
923072b8 92 let mut largest = &number_list[0];
3c0e092e 93
923072b8 94 for number in &number_list {
3c0e092e
XL
95 if number > largest {
96 largest = number;
97 }
98 }
99
100 println!("The largest number is {}", largest);
101
102 let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];
103
923072b8 104 let mut largest = &number_list[0];
3c0e092e 105
923072b8 106 for number in &number_list {
3c0e092e
XL
107 if number > largest {
108 largest = number;
109 }
110 }
111
112 println!("The largest number is {}", largest);
113}
114```
115
116Listing 10-2: Code to find the largest number in *two* lists of numbers
117
118Although this code works, duplicating code is tedious and error prone. We also
5e7ed085
FG
119have to remember to update the code in multiple places when we want to change
120it.
3c0e092e 121
5e7ed085
FG
122To eliminate this duplication, we’ll create an abstraction by defining a
123function that operates on any list of integers passed in a parameter. This
3c0e092e
XL
124solution makes our code clearer and lets us express the concept of finding the
125largest number in a list abstractly.
126
5e7ed085
FG
127In Listing 10-3, we extract the code that finds the largest number into a
128function named `largest`. Then we call the function to find the largest number
129in the two lists from Listing 10-2. We could also use the function on any other
130list of `i32` values we might have in the future.
131
3c0e092e
XL
132Filename: src/main.rs
133
134```
923072b8
FG
135fn largest(list: &[i32]) -> &i32 {
136 let mut largest = &list[0];
3c0e092e 137
923072b8 138 for item in list {
3c0e092e
XL
139 if item > largest {
140 largest = item;
141 }
142 }
143
144 largest
145}
146
147fn main() {
148 let number_list = vec![34, 50, 25, 100, 65];
149
150 let result = largest(&number_list);
151 println!("The largest number is {}", result);
152
153 let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];
154
155 let result = largest(&number_list);
156 println!("The largest number is {}", result);
157}
158```
159
160Listing 10-3: Abstracted code to find the largest number in two lists
161
162The `largest` function has a parameter called `list`, which represents any
5e7ed085
FG
163concrete slice of `i32` values we might pass into the function. As a result,
164when we call the function, the code runs on the specific values that we pass
923072b8 165in.
3c0e092e 166
923072b8 167In summary, here are the steps we took to change the code from Listing 10-2 to
3c0e092e
XL
168Listing 10-3:
169
923072b8
FG
170<!---
171"In summary"?
172/JT --->
173<!-- I believe "In sum" to be fine, but other people have been confused by it
174as well, so I'm ok changing it. /Carol -->
175
3c0e092e
XL
1761. Identify duplicate code.
1772. Extract the duplicate code into the body of the function and specify the
178 inputs and return values of that code in the function signature.
1793. Update the two instances of duplicated code to call the function instead.
180
5e7ed085
FG
181Next, we’ll use these same steps with generics to reduce code duplication. In
182the same way that the function body can operate on an abstract `list` instead
183of specific values, generics allow code to operate on abstract types.
3c0e092e
XL
184
185For example, say we had two functions: one that finds the largest item in a
186slice of `i32` values and one that finds the largest item in a slice of `char`
187values. How would we eliminate that duplication? Let’s find out!
188
189## Generic Data Types
190
5e7ed085 191We use generics to create definitions for items like function signatures or
3c0e092e
XL
192structs, which we can then use with many different concrete data types. Let’s
193first look at how to define functions, structs, enums, and methods using
194generics. Then we’ll discuss how generics affect code performance.
195
196### In Function Definitions
197
198When defining a function that uses generics, we place the generics in the
199signature of the function where we would usually specify the data types of the
200parameters and return value. Doing so makes our code more flexible and provides
201more functionality to callers of our function while preventing code duplication.
202
203Continuing with our `largest` function, Listing 10-4 shows two functions that
5e7ed085
FG
204both find the largest value in a slice. We'll then combine these into a single
205function that uses generics.
3c0e092e
XL
206
207Filename: src/main.rs
208
209```
923072b8
FG
210fn largest_i32(list: &[i32]) -> &i32 {
211 let mut largest = &list[0];
3c0e092e 212
923072b8 213 for item in list {
3c0e092e
XL
214 if item > largest {
215 largest = item;
216 }
217 }
218
219 largest
220}
221
923072b8
FG
222fn largest_char(list: &[char]) -> &char {
223 let mut largest = &list[0];
3c0e092e 224
923072b8 225 for item in list {
3c0e092e
XL
226 if item > largest {
227 largest = item;
228 }
229 }
230
231 largest
232}
233
234fn main() {
235 let number_list = vec![34, 50, 25, 100, 65];
236
237 let result = largest_i32(&number_list);
238 println!("The largest number is {}", result);
239
240 let char_list = vec!['y', 'm', 'a', 'q'];
241
242 let result = largest_char(&char_list);
243 println!("The largest char is {}", result);
244}
245```
246
247Listing 10-4: Two functions that differ only in their names and the types in
248their signatures
249
250The `largest_i32` function is the one we extracted in Listing 10-3 that finds
251the largest `i32` in a slice. The `largest_char` function finds the largest
252`char` in a slice. The function bodies have the same code, so let’s eliminate
253the duplication by introducing a generic type parameter in a single function.
254
5e7ed085
FG
255To parameterize the types in a new single function, we need to name the type
256parameter, just as we do for the value parameters to a function. You can use
257any identifier as a type parameter name. But we’ll use `T` because, by
3c0e092e
XL
258convention, parameter names in Rust are short, often just a letter, and Rust’s
259type-naming convention is CamelCase. Short for “type,” `T` is the default
260choice of most Rust programmers.
261
262When we use a parameter in the body of the function, we have to declare the
263parameter name in the signature so the compiler knows what that name means.
264Similarly, when we use a type parameter name in a function signature, we have
265to declare the type parameter name before we use it. To define the generic
266`largest` function, place type name declarations inside angle brackets, `<>`,
267between the name of the function and the parameter list, like this:
268
269```
923072b8 270fn largest<T>(list: &[T]) -> &T {
3c0e092e
XL
271```
272
273We read this definition as: the function `largest` is generic over some type
274`T`. This function has one parameter named `list`, which is a slice of values
923072b8 275of type `T`. The `largest` function will return a reference to a value of the
3c0e092e
XL
276same type `T`.
277
278Listing 10-5 shows the combined `largest` function definition using the generic
279data type in its signature. The listing also shows how we can call the function
280with either a slice of `i32` values or `char` values. Note that this code won’t
281compile yet, but we’ll fix it later in this chapter.
282
283Filename: src/main.rs
284
285```
923072b8
FG
286fn largest<T>(list: &[T]) -> &T {
287 let mut largest = &list[0];
3c0e092e 288
923072b8 289 for item in list {
3c0e092e
XL
290 if item > largest {
291 largest = item;
292 }
293 }
294
295 largest
296}
297
298fn main() {
299 let number_list = vec![34, 50, 25, 100, 65];
300
301 let result = largest(&number_list);
302 println!("The largest number is {}", result);
303
304 let char_list = vec!['y', 'm', 'a', 'q'];
305
306 let result = largest(&char_list);
307 println!("The largest char is {}", result);
308}
309```
310
5e7ed085
FG
311Listing 10-5: The `largest` function using generic type parameters; this
312doesn’t yet compile yet
3c0e092e
XL
313
314If we compile this code right now, we’ll get this error:
315
316```
317error[E0369]: binary operation `>` cannot be applied to type `T`
318 --> src/main.rs:5:17
319 |
3205 | if item > largest {
321 | ---- ^ ------- T
322 | |
323 | T
324 |
325help: consider restricting type parameter `T`
326 |
3271 | fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> T {
328 | ^^^^^^^^^^^^^^^^^^^^^^
329```
330
923072b8
FG
331The help text mentions `std::cmp::PartialOrd`, which is a *trait*, and we’re
332going to talk about traits in the next section. For now, know that this error
333states that the body of `largest` won’t work for all possible types that `T`
334could be. Because we want to compare values of type `T` in the body, we can
335only use types whose values can be ordered. To enable comparisons, the standard
336library has the `std::cmp::PartialOrd` trait that you can implement on types
337(see Appendix C for more on this trait). By following the help text's
338suggestion, we restrict the types valid for `T` to only those that implement
339`PartialOrd` and this example will compile, because the standard library
340implements `PartialOrd` on both `i32` and `char`.
341
342<!---
343The wording at the end of the above paragraph feels a little odd. For the
344"You’ll learn how to specify that a generic type has a particular trait in the
345“Traits as Parameters” section." -- the error message above tells you how to
346maybe fix it.
347
348Well, it *could* fix it but the way the example is written adds multiple
349constraints.
350
351Do we want to leave this example unfinished and move onto other topics for a
352bit or revise the example so it's more self-contained, allowing the compiler to
353help us and later revisit after we've learned more?
354/JT --->
355<!-- I've modified the example and explanation just slightly so that only
356adding the `PartialOrd` trait as suggested here will fix it completely, perhaps
357leaving the reader hanging a little bit less. It's really hard to teach
358generics and trait bounds, though, because you can't do much with generics
359unless you have trait bounds too (and can't learn why you'd want trait bounds
360without knowing about generics). /Carol -->
3c0e092e
XL
361
362### In Struct Definitions
363
364We can also define structs to use a generic type parameter in one or more
5e7ed085
FG
365fields using the `<>` syntax. Listing 10-6 defines a `Point<T>` struct to hold
366`x` and `y` coordinate values of any type.
3c0e092e
XL
367
368Filename: src/main.rs
369
370```
371struct Point<T> {
372 x: T,
373 y: T,
374}
375
376fn main() {
377 let integer = Point { x: 5, y: 10 };
378 let float = Point { x: 1.0, y: 4.0 };
379}
380```
381
382Listing 10-6: A `Point<T>` struct that holds `x` and `y` values of type `T`
383
384The syntax for using generics in struct definitions is similar to that used in
385function definitions. First, we declare the name of the type parameter inside
5e7ed085
FG
386angle brackets just after the name of the struct. Then we use the generic type
387in the struct definition where we would otherwise specify concrete data types.
3c0e092e
XL
388
389Note that because we’ve used only one generic type to define `Point<T>`, this
390definition says that the `Point<T>` struct is generic over some type `T`, and
391the fields `x` and `y` are *both* that same type, whatever that type may be. If
392we create an instance of a `Point<T>` that has values of different types, as in
393Listing 10-7, our code won’t compile.
394
395Filename: src/main.rs
396
397```
398struct Point<T> {
399 x: T,
400 y: T,
401}
402
403fn main() {
404 let wont_work = Point { x: 5, y: 4.0 };
405}
406```
407
408Listing 10-7: The fields `x` and `y` must be the same type because both have
409the same generic data type `T`.
410
5e7ed085
FG
411In this example, when we assign the integer value 5 to `x`, we let the compiler
412know that the generic type `T` will be an integer for this instance of
3c0e092e
XL
413`Point<T>`. Then when we specify 4.0 for `y`, which we’ve defined to have the
414same type as `x`, we’ll get a type mismatch error like this:
415
923072b8
FG
416<!---
417Not sure how or where we might want to call this out, but this is also how
418type inference in Rust works. If we don't know the type, we look for how it's
419used. That fresh type becomes a concrete type, and any use after that which
420is different than we expect becomes an error.
421
422fn main() {
423 let mut x;
424
425 x = 5;
426 x = 4.0;
427}
428
429Also gives:
430 |
4312 | let mut x;
432 | ----- expected due to the type of this binding
433...
4345 | x = 4.0;
435 | ^^^ expected integer, found floating-point number
436
437/JT --->
438<!-- Yeah, it's kind of neat trivia, but doesn't really fit here I don't think.
439/Carol -->
440
3c0e092e
XL
441```
442error[E0308]: mismatched types
443 --> src/main.rs:7:38
444 |
4457 | let wont_work = Point { x: 5, y: 4.0 };
446 | ^^^ expected integer, found floating-point number
447```
448
449To define a `Point` struct where `x` and `y` are both generics but could have
450different types, we can use multiple generic type parameters. For example, in
5e7ed085
FG
451Listing 10-8, we change the definition of `Point` to be generic over types `T`
452and `U` where `x` is of type `T` and `y` is of type `U`.
3c0e092e
XL
453
454Filename: src/main.rs
455
456```
457struct Point<T, U> {
458 x: T,
459 y: U,
460}
461
462fn main() {
463 let both_integer = Point { x: 5, y: 10 };
464 let both_float = Point { x: 1.0, y: 4.0 };
465 let integer_and_float = Point { x: 5, y: 4.0 };
466}
467```
468
469Listing 10-8: A `Point<T, U>` generic over two types so that `x` and `y` can be
470values of different types
471
472Now all the instances of `Point` shown are allowed! You can use as many generic
473type parameters in a definition as you want, but using more than a few makes
5e7ed085
FG
474your code hard to read. If you're finding you need lots of generic types in
475your code, it could indicate that your code needs restructuring into smaller
476pieces.
3c0e092e
XL
477
478### In Enum Definitions
479
480As we did with structs, we can define enums to hold generic data types in their
481variants. Let’s take another look at the `Option<T>` enum that the standard
482library provides, which we used in Chapter 6:
483
484```
485enum Option<T> {
486 Some(T),
487 None,
488}
489```
490
5e7ed085
FG
491This definition should now make more sense to you. As you can see, the
492`Option<T>` enum is generic over type `T` and has two variants: `Some`, which
3c0e092e 493holds one value of type `T`, and a `None` variant that doesn’t hold any value.
5e7ed085 494By using the `Option<T>` enum, we can express the abstract concept of an
3c0e092e
XL
495optional value, and because `Option<T>` is generic, we can use this abstraction
496no matter what the type of the optional value is.
497
498Enums can use multiple generic types as well. The definition of the `Result`
499enum that we used in Chapter 9 is one example:
500
501```
502enum Result<T, E> {
503 Ok(T),
504 Err(E),
505}
506```
507
508The `Result` enum is generic over two types, `T` and `E`, and has two variants:
509`Ok`, which holds a value of type `T`, and `Err`, which holds a value of type
510`E`. This definition makes it convenient to use the `Result` enum anywhere we
511have an operation that might succeed (return a value of some type `T`) or fail
512(return an error of some type `E`). In fact, this is what we used to open a
513file in Listing 9-3, where `T` was filled in with the type `std::fs::File` when
514the file was opened successfully and `E` was filled in with the type
515`std::io::Error` when there were problems opening the file.
516
517When you recognize situations in your code with multiple struct or enum
518definitions that differ only in the types of the values they hold, you can
519avoid duplication by using generic types instead.
520
521### In Method Definitions
522
523We can implement methods on structs and enums (as we did in Chapter 5) and use
524generic types in their definitions, too. Listing 10-9 shows the `Point<T>`
525struct we defined in Listing 10-6 with a method named `x` implemented on it.
526
527Filename: src/main.rs
528
529```
530struct Point<T> {
531 x: T,
532 y: T,
533}
534
535impl<T> Point<T> {
536 fn x(&self) -> &T {
537 &self.x
538 }
539}
540
541fn main() {
542 let p = Point { x: 5, y: 10 };
543
544 println!("p.x = {}", p.x());
545}
546```
547
923072b8
FG
548<!---
549
550The above code gives a warning for the unused `y`. Maybe we can print both
551`x` and `y`?
552
553/JT --->
554<!-- In general, I'm not worried about unused code warnings, there's a lot of
555examples that have unused code because they're small examples. I don't think
556there's much value in adding a method and printing `y` as well. /Carol -->
557
3c0e092e
XL
558Listing 10-9: Implementing a method named `x` on the `Point<T>` struct that
559will return a reference to the `x` field of type `T`
560
561Here, we’ve defined a method named `x` on `Point<T>` that returns a reference
562to the data in the field `x`.
563
5e7ed085 564Note that we have to declare `T` just after `impl` so we can use `T` to specify
3c0e092e
XL
565that we’re implementing methods on the type `Point<T>`. By declaring `T` as a
566generic type after `impl`, Rust can identify that the type in the angle
5e7ed085
FG
567brackets in `Point` is a generic type rather than a concrete type. We could
568have chosen a different name for this generic parameter than the generic
569parameter declared in the struct definition, but using the same name is
570conventional. Methods written within an `impl` that declares the generic type
571will be defined on any instance of the type, no matter what concrete type ends
572up substituting for the generic type.
573
574We can also specify constraints on generic types when defining methods on the
575type. We could, for example, implement methods only on `Point<f32>` instances
576rather than on `Point<T>` instances with any generic type. In Listing 10-10 we
577use the concrete type `f32`, meaning we don’t declare any types after `impl`.
3c0e092e
XL
578
579Filename: src/main.rs
580
581```
582impl Point<f32> {
583 fn distance_from_origin(&self) -> f32 {
584 (self.x.powi(2) + self.y.powi(2)).sqrt()
585 }
586}
587```
588
589Listing 10-10: An `impl` block that only applies to a struct with a particular
590concrete type for the generic type parameter `T`
591
5e7ed085
FG
592This code means the type `Point<f32>` will have a `distance_from_origin`
593method; other instances of `Point<T>` where `T` is not of type `f32` will not
594have this method defined. The method measures how far our point is from the
595point at coordinates (0.0, 0.0) and uses mathematical operations that are
596available only for floating point types.
3c0e092e
XL
597
598Generic type parameters in a struct definition aren’t always the same as those
5e7ed085 599you use in that same struct’s method signatures. Listing 10-11 uses the generic
3c0e092e
XL
600types `X1` and `Y1` for the `Point` struct and `X2` `Y2` for the `mixup` method
601signature to make the example clearer. The method creates a new `Point`
602instance with the `x` value from the `self` `Point` (of type `X1`) and the `y`
603value from the passed-in `Point` (of type `Y2`).
604
605Filename: src/main.rs
606
607```
608struct Point<X1, Y1> {
609 x: X1,
610 y: Y1,
611}
612
613impl<X1, Y1> Point<X1, Y1> {
614 fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
615 Point {
616 x: self.x,
617 y: other.y,
618 }
619 }
620}
621
622fn main() {
623 let p1 = Point { x: 5, y: 10.4 };
624 let p2 = Point { x: "Hello", y: 'c' };
625
626 let p3 = p1.mixup(p2);
627
628 println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
629}
630```
631
5e7ed085 632Listing 10-11: A method that uses generic types different from its struct’s
3c0e092e
XL
633definition
634
635In `main`, we’ve defined a `Point` that has an `i32` for `x` (with value `5`)
636and an `f64` for `y` (with value `10.4`). The `p2` variable is a `Point` struct
637that has a string slice for `x` (with value `"Hello"`) and a `char` for `y`
638(with value `c`). Calling `mixup` on `p1` with the argument `p2` gives us `p3`,
639which will have an `i32` for `x`, because `x` came from `p1`. The `p3` variable
640will have a `char` for `y`, because `y` came from `p2`. The `println!` macro
641call will print `p3.x = 5, p3.y = c`.
642
643The purpose of this example is to demonstrate a situation in which some generic
644parameters are declared with `impl` and some are declared with the method
645definition. Here, the generic parameters `X1` and `Y1` are declared after
646`impl` because they go with the struct definition. The generic parameters `X2`
647and `Y2` are declared after `fn mixup`, because they’re only relevant to the
648method.
649
650### Performance of Code Using Generics
651
5e7ed085
FG
652You might be wondering whether there is a runtime cost when using generic type
653parameters. The good news is that using generic types won't make your run any
654slower than it would with concrete types.
3c0e092e 655
5e7ed085 656Rust accomplishes this by performing monomorphization of the code using
3c0e092e
XL
657generics at compile time. *Monomorphization* is the process of turning generic
658code into specific code by filling in the concrete types that are used when
5e7ed085
FG
659compiled. In this process, the compiler does the opposite of the steps we used
660to create the generic function in Listing 10-5: the compiler looks at all the
661places where generic code is called and generates code for the concrete types
662the generic code is called with.
3c0e092e 663
5e7ed085 664Let’s look at how this works by using the standard library’s generic
3c0e092e
XL
665`Option<T>` enum:
666
667```
668let integer = Some(5);
669let float = Some(5.0);
670```
671
672When Rust compiles this code, it performs monomorphization. During that
673process, the compiler reads the values that have been used in `Option<T>`
674instances and identifies two kinds of `Option<T>`: one is `i32` and the other
923072b8
FG
675is `f64`. As such, it expands the generic definition of `Option<T>` into two
676definitions specialized to `i32` and `f64`, thereby replacing the generic
677definition with the specific ones.
678
679<!---
3c0e092e 680
923072b8
FG
681We may want to be clear in the above it doesn't actually do this, as you
682wouldn't be able to write `enum Option_i32` in your code as it would clash.
683
684/JT --->
685<!-- I've reworded the last sentence in the above paragraph and the next
686sentence to hopefully sidestep the issue JT pointed out. /Carol -->
687
688The monomorphized version of the code looks similar to the following (the
689compiler uses different names than what we’re using here for illustration):
3c0e092e
XL
690
691Filename: src/main.rs
692
693```
694enum Option_i32 {
695 Some(i32),
696 None,
697}
698
699enum Option_f64 {
700 Some(f64),
701 None,
702}
703
704fn main() {
705 let integer = Option_i32::Some(5);
706 let float = Option_f64::Some(5.0);
707}
708```
709
5e7ed085
FG
710The generic `Option<T>` is replaced with the specific definitions created by
711the compiler. Because Rust compiles generic code into code that specifies the
712type in each instance, we pay no runtime cost for using generics. When the code
713runs, it performs just as it would if we had duplicated each definition by
714hand. The process of monomorphization makes Rust’s generics extremely efficient
715at runtime.
3c0e092e
XL
716
717## Traits: Defining Shared Behavior
718
5e7ed085
FG
719A *trait* defines functionality a particular type has and can share with other
720types. We can use traits to define shared behavior in an abstract way. We can
721use *trait bounds* to specify that a generic type can be any type that has
722certain behavior.
3c0e092e
XL
723
724> Note: Traits are similar to a feature often called *interfaces* in other
725> languages, although with some differences.
726
727### Defining a Trait
728
729A type’s behavior consists of the methods we can call on that type. Different
730types share the same behavior if we can call the same methods on all of those
731types. Trait definitions are a way to group method signatures together to
732define a set of behaviors necessary to accomplish some purpose.
733
734For example, let’s say we have multiple structs that hold various kinds and
735amounts of text: a `NewsArticle` struct that holds a news story filed in a
736particular location and a `Tweet` that can have at most 280 characters along
737with metadata that indicates whether it was a new tweet, a retweet, or a reply
738to another tweet.
739
740We want to make a media aggregator library crate named `aggregator` that can
741display summaries of data that might be stored in a `NewsArticle` or `Tweet`
742instance. To do this, we need a summary from each type, and we’ll request
743that summary by calling a `summarize` method on an instance. Listing 10-12
744shows the definition of a public `Summary` trait that expresses this behavior.
745
746Filename: src/lib.rs
747
748```
749pub trait Summary {
750 fn summarize(&self) -> String;
751}
752```
753
754Listing 10-12: A `Summary` trait that consists of the behavior provided by a
755`summarize` method
756
757Here, we declare a trait using the `trait` keyword and then the trait’s name,
758which is `Summary` in this case. We’ve also declared the trait as `pub` so that
759crates depending on this crate can make use of this trait too, as we’ll see in
760a few examples. Inside the curly brackets, we declare the method signatures
761that describe the behaviors of the types that implement this trait, which in
762this case is `fn summarize(&self) -> String`.
763
764After the method signature, instead of providing an implementation within curly
765brackets, we use a semicolon. Each type implementing this trait must provide
766its own custom behavior for the body of the method. The compiler will enforce
767that any type that has the `Summary` trait will have the method `summarize`
768defined with this signature exactly.
769
770A trait can have multiple methods in its body: the method signatures are listed
771one per line and each line ends in a semicolon.
772
773### Implementing a Trait on a Type
774
775Now that we’ve defined the desired signatures of the `Summary` trait’s methods,
776we can implement it on the types in our media aggregator. Listing 10-13 shows
777an implementation of the `Summary` trait on the `NewsArticle` struct that uses
778the headline, the author, and the location to create the return value of
779`summarize`. For the `Tweet` struct, we define `summarize` as the username
780followed by the entire text of the tweet, assuming that tweet content is
781already limited to 280 characters.
782
783Filename: src/lib.rs
784
785```
786pub struct NewsArticle {
787 pub headline: String,
788 pub location: String,
789 pub author: String,
790 pub content: String,
791}
792
793impl Summary for NewsArticle {
794 fn summarize(&self) -> String {
795 format!("{}, by {} ({})", self.headline, self.author, self.location)
796 }
797}
798
799pub struct Tweet {
800 pub username: String,
801 pub content: String,
802 pub reply: bool,
803 pub retweet: bool,
804}
805
806impl Summary for Tweet {
807 fn summarize(&self) -> String {
808 format!("{}: {}", self.username, self.content)
809 }
810}
811```
812
813Listing 10-13: Implementing the `Summary` trait on the `NewsArticle` and
814`Tweet` types
815
816Implementing a trait on a type is similar to implementing regular methods. The
5e7ed085
FG
817difference is that after `impl`, we put the trait name we want to implement,
818then use the `for` keyword, and then specify the name of the type we want to
819implement the trait for. Within the `impl` block, we put the method signatures
820that the trait definition has defined. Instead of adding a semicolon after each
821signature, we use curly brackets and fill in the method body with the specific
822behavior that we want the methods of the trait to have for the particular type.
823
824<!-- NOTE TO ADD SOME NUMBER INDICATORS HERE IN THE WORD FILES -->
3c0e092e
XL
825
826Now that the library has implemented the `Summary` trait on `NewsArticle` and
827`Tweet`, users of the crate can call the trait methods on instances of
828`NewsArticle` and `Tweet` in the same way we call regular methods. The only
5e7ed085
FG
829difference is that the user must bring the trait into scope as well as the
830types. Here’s an example of how a binary crate could use our `aggregator`
831library crate:
3c0e092e
XL
832
833```
834use aggregator::{Summary, Tweet};
835
836fn main() {
837 let tweet = Tweet {
838 username: String::from("horse_ebooks"),
839 content: String::from(
840 "of course, as you probably already know, people",
841 ),
842 reply: false,
843 retweet: false,
844 };
845
846 println!("1 new tweet: {}", tweet.summarize());
847}
848```
849
850This code prints `1 new tweet: horse_ebooks: of course, as you probably already
851know, people`.
852
853Other crates that depend on the `aggregator` crate can also bring the `Summary`
5e7ed085
FG
854trait into scope to implement `Summary` on their own types. One restriction to
855note is that we can implement a trait on a type only if at least one of the
856trait or the type is local to our crate. For example, we can implement standard
857library traits like `Display` on a custom type like `Tweet` as part of our
858`aggregator` crate functionality, because the type `Tweet` is local to our
859`aggregator` crate. We can also implement `Summary` on `Vec<T>` in our
860`aggregator` crate, because the trait `Summary` is local to our `aggregator`
861crate.
3c0e092e
XL
862
863But we can’t implement external traits on external types. For example, we can’t
864implement the `Display` trait on `Vec<T>` within our `aggregator` crate,
5e7ed085
FG
865because `Display` and `Vec<T>` are both defined in the standard library and
866aren’t local to our `aggregator` crate. This restriction is part of a property
867called *coherence*, and more specifically the *orphan rule*, so named because
868the parent type is not present. This rule ensures that other people’s code
869can’t break your code and vice versa. Without the rule, two crates could
3c0e092e
XL
870implement the same trait for the same type, and Rust wouldn’t know which
871implementation to use.
872
873### Default Implementations
874
875Sometimes it’s useful to have default behavior for some or all of the methods
876in a trait instead of requiring implementations for all methods on every type.
877Then, as we implement the trait on a particular type, we can keep or override
878each method’s default behavior.
879
5e7ed085
FG
880In Listing 10-14 we specify a default string for the `summarize` method of the
881`Summary` trait instead of only defining the method signature, as we did in
882Listing 10-12.
3c0e092e
XL
883
884Filename: src/lib.rs
885
886```
887pub trait Summary {
888 fn summarize(&self) -> String {
889 String::from("(Read more...)")
890 }
891}
892```
893
5e7ed085 894Listing 10-14: Defining a `Summary` trait with a default implementation of
3c0e092e
XL
895the `summarize` method
896
5e7ed085
FG
897To use a default implementation to summarize instances of `NewsArticle`, we
898specify an empty `impl` block with `impl Summary for NewsArticle {}`.
3c0e092e
XL
899
900Even though we’re no longer defining the `summarize` method on `NewsArticle`
901directly, we’ve provided a default implementation and specified that
902`NewsArticle` implements the `Summary` trait. As a result, we can still call
903the `summarize` method on an instance of `NewsArticle`, like this:
904
905```
906let article = NewsArticle {
907 headline: String::from("Penguins win the Stanley Cup Championship!"),
908 location: String::from("Pittsburgh, PA, USA"),
909 author: String::from("Iceburgh"),
910 content: String::from(
911 "The Pittsburgh Penguins once again are the best \
912 hockey team in the NHL.",
913 ),
914};
915
916println!("New article available! {}", article.summarize());
917```
918
919This code prints `New article available! (Read more...)`.
920
5e7ed085
FG
921Creating a default implementation doesn’t require us to change anything about
922the implementation of `Summary` on `Tweet` in Listing 10-13. The reason is that
923the syntax for overriding a default implementation is the same as the syntax
924for implementing a trait method that doesn’t have a default implementation.
3c0e092e
XL
925
926Default implementations can call other methods in the same trait, even if those
927other methods don’t have a default implementation. In this way, a trait can
928provide a lot of useful functionality and only require implementors to specify
929a small part of it. For example, we could define the `Summary` trait to have a
930`summarize_author` method whose implementation is required, and then define a
931`summarize` method that has a default implementation that calls the
932`summarize_author` method:
933
934```
935pub trait Summary {
936 fn summarize_author(&self) -> String;
937
938 fn summarize(&self) -> String {
939 format!("(Read more from {}...)", self.summarize_author())
940 }
941}
942```
943
944To use this version of `Summary`, we only need to define `summarize_author`
945when we implement the trait on a type:
946
947```
948impl Summary for Tweet {
949 fn summarize_author(&self) -> String {
950 format!("@{}", self.username)
951 }
952}
953```
954
955After we define `summarize_author`, we can call `summarize` on instances of the
956`Tweet` struct, and the default implementation of `summarize` will call the
957definition of `summarize_author` that we’ve provided. Because we’ve implemented
958`summarize_author`, the `Summary` trait has given us the behavior of the
959`summarize` method without requiring us to write any more code.
960
961```
962let tweet = Tweet {
963 username: String::from("horse_ebooks"),
964 content: String::from(
965 "of course, as you probably already know, people",
966 ),
967 reply: false,
968 retweet: false,
969};
970
971println!("1 new tweet: {}", tweet.summarize());
972```
973
974This code prints `1 new tweet: (Read more from @horse_ebooks...)`.
975
976Note that it isn’t possible to call the default implementation from an
977overriding implementation of that same method.
978
979### Traits as Parameters
980
981Now that you know how to define and implement traits, we can explore how to use
5e7ed085
FG
982traits to define functions that accept many different types. We'll use the
983`Summary` trait we implemented on the `NewsArticle` and `Tweet` types in
984Listing 10-13 to define a `notify` function that calls the `summarize` method
985on its `item` parameter, which is of some type that implements the `Summary`
986trait. To do this, we use the `impl Trait` syntax, like this:
3c0e092e
XL
987
988```
989pub fn notify(item: &impl Summary) {
990 println!("Breaking news! {}", item.summarize());
991}
992```
993
994Instead of a concrete type for the `item` parameter, we specify the `impl`
995keyword and the trait name. This parameter accepts any type that implements the
996specified trait. In the body of `notify`, we can call any methods on `item`
997that come from the `Summary` trait, such as `summarize`. We can call `notify`
998and pass in any instance of `NewsArticle` or `Tweet`. Code that calls the
999function with any other type, such as a `String` or an `i32`, won’t compile
1000because those types don’t implement `Summary`.
1001
1002#### Trait Bound Syntax
1003
5e7ed085
FG
1004The `impl Trait` syntax works for straightforward cases but is actually syntax
1005sugar for a longer form known as a *trait bound*; it looks like this:
3c0e092e
XL
1006
1007```
1008pub fn notify<T: Summary>(item: &T) {
1009 println!("Breaking news! {}", item.summarize());
1010}
1011```
1012
1013This longer form is equivalent to the example in the previous section but is
1014more verbose. We place trait bounds with the declaration of the generic type
1015parameter after a colon and inside angle brackets.
1016
1017The `impl Trait` syntax is convenient and makes for more concise code in simple
5e7ed085 1018cases, while the fuller trait bound syntax can express more complexity in other
923072b8
FG
1019cases. For example, we can have two parameters that implement `Summary`. Doing
1020so with the `impl Trait` syntax looks like this:
3c0e092e
XL
1021
1022```
1023pub fn notify(item1: &impl Summary, item2: &impl Summary) {
1024```
1025
5e7ed085
FG
1026Using `impl Trait` is appropriate if we want this function to allow `item1` and
1027`item2` to have different types (as long as both types implement `Summary`). If
1028we want to force both parameters to have the same type, however, we must use a
1029trait bound, like this:
3c0e092e
XL
1030
1031```
1032pub fn notify<T: Summary>(item1: &T, item2: &T) {
1033```
1034
1035The generic type `T` specified as the type of the `item1` and `item2`
1036parameters constrains the function such that the concrete type of the value
1037passed as an argument for `item1` and `item2` must be the same.
1038
1039#### Specifying Multiple Trait Bounds with the `+` Syntax
1040
1041We can also specify more than one trait bound. Say we wanted `notify` to use
5e7ed085
FG
1042display formatting as well as `summarize` on `item`: we specify in the `notify`
1043definition that `item` must implement both `Display` and `Summary`. We can do
1044so using the `+` syntax:
3c0e092e
XL
1045
1046```
1047pub fn notify(item: &(impl Summary + Display)) {
1048```
1049
1050The `+` syntax is also valid with trait bounds on generic types:
1051
1052```
1053pub fn notify<T: Summary + Display>(item: &T) {
1054```
1055
1056With the two trait bounds specified, the body of `notify` can call `summarize`
1057and use `{}` to format `item`.
1058
1059#### Clearer Trait Bounds with `where` Clauses
1060
1061Using too many trait bounds has its downsides. Each generic has its own trait
1062bounds, so functions with multiple generic type parameters can contain lots of
1063trait bound information between the function’s name and its parameter list,
1064making the function signature hard to read. For this reason, Rust has alternate
1065syntax for specifying trait bounds inside a `where` clause after the function
1066signature. So instead of writing this:
1067
1068```
1069fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {
1070```
1071
1072we can use a `where` clause, like this:
1073
1074```
1075fn some_function<T, U>(t: &T, u: &U) -> i32
1076 where T: Display + Clone,
1077 U: Clone + Debug
1078{
1079```
1080
1081This function’s signature is less cluttered: the function name, parameter list,
1082and return type are close together, similar to a function without lots of trait
1083bounds.
1084
1085### Returning Types that Implement Traits
1086
1087We can also use the `impl Trait` syntax in the return position to return a
1088value of some type that implements a trait, as shown here:
1089
1090```
1091fn returns_summarizable() -> impl Summary {
1092 Tweet {
1093 username: String::from("horse_ebooks"),
1094 content: String::from(
1095 "of course, as you probably already know, people",
1096 ),
1097 reply: false,
1098 retweet: false,
1099 }
1100}
1101```
1102
1103By using `impl Summary` for the return type, we specify that the
1104`returns_summarizable` function returns some type that implements the `Summary`
1105trait without naming the concrete type. In this case, `returns_summarizable`
5e7ed085 1106returns a `Tweet`, but the code calling this function doesn’t need to know that.
3c0e092e 1107
5e7ed085
FG
1108The ability to specify a return type only by the trait it implements is
1109especially useful in the context of closures and iterators, which we cover in
1110Chapter 13. Closures and iterators create types that only the compiler knows or
1111types that are very long to specify. The `impl Trait` syntax lets you concisely
1112specify that a function returns some type that implements the `Iterator` trait
1113without needing to write out a very long type.
3c0e092e
XL
1114
1115However, you can only use `impl Trait` if you’re returning a single type. For
1116example, this code that returns either a `NewsArticle` or a `Tweet` with the
1117return type specified as `impl Summary` wouldn’t work:
1118
1119```
1120fn returns_summarizable(switch: bool) -> impl Summary {
1121 if switch {
1122 NewsArticle {
1123 headline: String::from(
1124 "Penguins win the Stanley Cup Championship!",
1125 ),
1126 location: String::from("Pittsburgh, PA, USA"),
1127 author: String::from("Iceburgh"),
1128 content: String::from(
1129 "The Pittsburgh Penguins once again are the best \
1130 hockey team in the NHL.",
1131 ),
1132 }
1133 } else {
1134 Tweet {
1135 username: String::from("horse_ebooks"),
1136 content: String::from(
1137 "of course, as you probably already know, people",
1138 ),
1139 reply: false,
1140 retweet: false,
1141 }
1142 }
1143}
1144```
1145
1146Returning either a `NewsArticle` or a `Tweet` isn’t allowed due to restrictions
1147around how the `impl Trait` syntax is implemented in the compiler. We’ll cover
1148how to write a function with this behavior in the “Using Trait Objects That
923072b8 1149Allow for Values of Different Types” section of Chapter 17.
3c0e092e 1150
923072b8
FG
1151<!-- I've removed the whole "Fixing the `largest` Function with Trait Bounds"
1152section now that the example is slightly different and adding the one trait
1153bound as the compiler suggests fixed Listing 10-5 earlier. I've also renumbered
1154the following listings. /Carol-->
3c0e092e
XL
1155
1156### Using Trait Bounds to Conditionally Implement Methods
1157
1158By using a trait bound with an `impl` block that uses generic type parameters,
1159we can implement methods conditionally for types that implement the specified
923072b8
FG
1160traits. For example, the type `Pair<T>` in Listing 10-15 always implements the
1161`new` function to return a new instance of `Pair<T>` (recall from the “Defining
3c0e092e
XL
1162Methods” section of Chapter 5 that `Self` is a type alias for the type of the
1163`impl` block, which in this case is `Pair<T>`). But in the next `impl` block,
1164`Pair<T>` only implements the `cmp_display` method if its inner type `T`
1165implements the `PartialOrd` trait that enables comparison *and* the `Display`
1166trait that enables printing.
1167
1168Filename: src/lib.rs
1169
1170```
1171use std::fmt::Display;
1172
1173struct Pair<T> {
1174 x: T,
1175 y: T,
1176}
1177
1178impl<T> Pair<T> {
1179 fn new(x: T, y: T) -> Self {
1180 Self { x, y }
1181 }
1182}
1183
1184impl<T: Display + PartialOrd> Pair<T> {
1185 fn cmp_display(&self) {
1186 if self.x >= self.y {
1187 println!("The largest member is x = {}", self.x);
1188 } else {
1189 println!("The largest member is y = {}", self.y);
1190 }
1191 }
1192}
1193```
1194
923072b8 1195Listing 10-15: Conditionally implementing methods on a generic type depending
5e7ed085 1196on trait bounds
3c0e092e
XL
1197
1198We can also conditionally implement a trait for any type that implements
1199another trait. Implementations of a trait on any type that satisfies the trait
1200bounds are called *blanket implementations* and are extensively used in the
1201Rust standard library. For example, the standard library implements the
1202`ToString` trait on any type that implements the `Display` trait. The `impl`
1203block in the standard library looks similar to this code:
1204
1205```
1206impl<T: Display> ToString for T {
1207 // --snip--
1208}
1209```
1210
1211Because the standard library has this blanket implementation, we can call the
1212`to_string` method defined by the `ToString` trait on any type that implements
1213the `Display` trait. For example, we can turn integers into their corresponding
1214`String` values like this because integers implement `Display`:
1215
1216```
1217let s = 3.to_string();
1218```
1219
1220Blanket implementations appear in the documentation for the trait in the
1221“Implementors” section.
1222
1223Traits and trait bounds let us write code that uses generic type parameters to
1224reduce duplication but also specify to the compiler that we want the generic
1225type to have particular behavior. The compiler can then use the trait bound
1226information to check that all the concrete types used with our code provide the
1227correct behavior. In dynamically typed languages, we would get an error at
1228runtime if we called a method on a type which didn’t define the method. But Rust
1229moves these errors to compile time so we’re forced to fix the problems before
1230our code is even able to run. Additionally, we don’t have to write code that
1231checks for behavior at runtime because we’ve already checked at compile time.
1232Doing so improves performance without having to give up the flexibility of
1233generics.
1234
3c0e092e
XL
1235## Validating References with Lifetimes
1236
923072b8
FG
1237<!---
1238
1239meta comment: this chapter is already pretty hefty. We just went through both
1240generics and a whirlwind tour of traits. Lifetimes, while related to generics,
1241feel like you might want to give a five minute break between them, let those
1242sink in, and then pick up this topic.
1243
1244I noticed a couple topics we may want to touch on above for a bit of
1245completeness:
1246
1247* A closer look at how From/Into work and how they relate to each other.
1248* Using traits to specialize what you do when returning values.
1249 i.e., Why does `let four: u32 = "4".parse().unwrap();` work?
1250* Turbofish
1251
1252/JT --->
1253<!-- These comments are totally valid, but seeing as this revision is already
1254dragging on later than we were hoping, I don't really want to do large scale
1255reorganization at this point. /Carol -->
1256
5e7ed085
FG
1257Lifetimes are another kind of generic that we’ve already been using. Rather
1258than ensuring that a type has the behavior we want, lifetimes ensure that
1259references are valid as long as we need them to be.
1260
3c0e092e
XL
1261One detail we didn’t discuss in the “References and Borrowing” section in
1262Chapter 4 is that every reference in Rust has a *lifetime*, which is the scope
1263for which that reference is valid. Most of the time, lifetimes are implicit and
5e7ed085 1264inferred, just like most of the time, types are inferred. We only must annotate
3c0e092e
XL
1265types when multiple types are possible. In a similar way, we must annotate
1266lifetimes when the lifetimes of references could be related in a few different
1267ways. Rust requires us to annotate the relationships using generic lifetime
1268parameters to ensure the actual references used at runtime will definitely be
1269valid.
1270
1271Annotating lifetimes is not even a concept most other programming languages
1272have, so this is going to feel unfamiliar. Although we won’t cover lifetimes in
1273their entirety in this chapter, we’ll discuss common ways you might encounter
5e7ed085 1274lifetime syntax so you can get comfortable with the concept.
3c0e092e
XL
1275
1276### Preventing Dangling References with Lifetimes
1277
5e7ed085 1278The main aim of lifetimes is to prevent *dangling references*, which cause a
3c0e092e 1279program to reference data other than the data it’s intended to reference.
923072b8 1280Consider the program in Listing 10-16, which has an outer scope and an inner
3c0e092e
XL
1281scope.
1282
1283```
923072b8 1284fn main() {
3c0e092e
XL
1285 let r;
1286
1287 {
1288 let x = 5;
1289 r = &x;
1290 }
1291
1292 println!("r: {}", r);
1293}
1294```
1295
923072b8 1296Listing 10-16: An attempt to use a reference whose value has gone out of scope
3c0e092e 1297
923072b8 1298> Note: The examples in Listings 10-16, 10-17, and 10-23 declare variables
3c0e092e
XL
1299> without giving them an initial value, so the variable name exists in the
1300> outer scope. At first glance, this might appear to be in conflict with Rust’s
1301> having no null values. However, if we try to use a variable before giving it
1302> a value, we’ll get a compile-time error, which shows that Rust indeed does
1303> not allow null values.
1304
1305The outer scope declares a variable named `r` with no initial value, and the
1306inner scope declares a variable named `x` with the initial value of 5. Inside
1307the inner scope, we attempt to set the value of `r` as a reference to `x`. Then
1308the inner scope ends, and we attempt to print the value in `r`. This code won’t
1309compile because the value `r` is referring to has gone out of scope before we
1310try to use it. Here is the error message:
1311
1312```
1313error[E0597]: `x` does not live long enough
923072b8
FG
1314 --> src/main.rs:6:13
1315 |
13166 | r = &x;
1317 | ^^ borrowed value does not live long enough
13187 | }
1319 | - `x` dropped here while still borrowed
13208 |
13219 | println!("r: {}", r);
1322 | - borrow later used here
3c0e092e
XL
1323```
1324
1325The variable `x` doesn’t “live long enough.” The reason is that `x` will be out
1326of scope when the inner scope ends on line 7. But `r` is still valid for the
1327outer scope; because its scope is larger, we say that it “lives longer.” If
1328Rust allowed this code to work, `r` would be referencing memory that was
1329deallocated when `x` went out of scope, and anything we tried to do with `r`
1330wouldn’t work correctly. So how does Rust determine that this code is invalid?
1331It uses a borrow checker.
1332
1333### The Borrow Checker
1334
1335The Rust compiler has a *borrow checker* that compares scopes to determine
923072b8
FG
1336whether all borrows are valid. Listing 10-17 shows the same code as Listing
133710-16 but with annotations showing the lifetimes of the variables.
3c0e092e
XL
1338
1339```
923072b8 1340fn main() {
3c0e092e
XL
1341 let r; // ---------+-- 'a
1342 // |
1343 { // |
1344 let x = 5; // -+-- 'b |
1345 r = &x; // | |
1346 } // -+ |
1347 // |
1348 println!("r: {}", r); // |
1349} // ---------+
1350```
1351
923072b8 1352Listing 10-17: Annotations of the lifetimes of `r` and `x`, named `'a` and
3c0e092e
XL
1353`'b`, respectively
1354
1355Here, we’ve annotated the lifetime of `r` with `'a` and the lifetime of `x`
1356with `'b`. As you can see, the inner `'b` block is much smaller than the outer
1357`'a` lifetime block. At compile time, Rust compares the size of the two
1358lifetimes and sees that `r` has a lifetime of `'a` but that it refers to memory
1359with a lifetime of `'b`. The program is rejected because `'b` is shorter than
1360`'a`: the subject of the reference doesn’t live as long as the reference.
1361
923072b8 1362Listing 10-18 fixes the code so it doesn’t have a dangling reference and
3c0e092e
XL
1363compiles without any errors.
1364
1365```
923072b8 1366fn main() {
3c0e092e
XL
1367 let x = 5; // ----------+-- 'b
1368 // |
1369 let r = &x; // --+-- 'a |
1370 // | |
1371 println!("r: {}", r); // | |
1372 // --+ |
1373} // ----------+
1374```
1375
923072b8 1376Listing 10-18: A valid reference because the data has a longer lifetime than
3c0e092e
XL
1377the reference
1378
1379Here, `x` has the lifetime `'b`, which in this case is larger than `'a`. This
1380means `r` can reference `x` because Rust knows that the reference in `r` will
1381always be valid while `x` is valid.
1382
1383Now that you know where the lifetimes of references are and how Rust analyzes
1384lifetimes to ensure references will always be valid, let’s explore generic
1385lifetimes of parameters and return values in the context of functions.
1386
1387### Generic Lifetimes in Functions
1388
5e7ed085
FG
1389We’ll write a function that returns the longer of two string slices. This
1390function will take two string slices and return a single string slice. After
923072b8 1391we’ve implemented the `longest` function, the code in Listing 10-19 should
5e7ed085 1392print `The longest string is abcd`.
3c0e092e
XL
1393
1394Filename: src/main.rs
1395
1396```
1397fn main() {
1398 let string1 = String::from("abcd");
1399 let string2 = "xyz";
1400
1401 let result = longest(string1.as_str(), string2);
1402 println!("The longest string is {}", result);
1403}
1404```
1405
923072b8 1406Listing 10-19: A `main` function that calls the `longest` function to find the
3c0e092e
XL
1407longer of two string slices
1408
1409Note that we want the function to take string slices, which are references,
5e7ed085
FG
1410rather than strings, because we don’t want the `longest` function to take
1411ownership of its parameters. Refer to the “String Slices as Parameters” section
1412in Chapter 4 for more discussion about why the parameters we use in Listing
923072b8 141310-19 are the ones we want.
3c0e092e 1414
923072b8 1415If we try to implement the `longest` function as shown in Listing 10-20, it
3c0e092e
XL
1416won’t compile.
1417
1418Filename: src/main.rs
1419
1420```
1421fn longest(x: &str, y: &str) -> &str {
1422 if x.len() > y.len() {
1423 x
1424 } else {
1425 y
1426 }
1427}
1428```
1429
923072b8 1430Listing 10-20: An implementation of the `longest` function that returns the
3c0e092e
XL
1431longer of two string slices but does not yet compile
1432
1433Instead, we get the following error that talks about lifetimes:
1434
1435```
1436error[E0106]: missing lifetime specifier
1437 --> src/main.rs:9:33
1438 |
14399 | fn longest(x: &str, y: &str) -> &str {
1440 | ---- ---- ^ expected named lifetime parameter
1441 |
1442 = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
1443help: consider introducing a named lifetime parameter
1444 |
14459 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
1446 | ^^^^ ^^^^^^^ ^^^^^^^ ^^^
1447```
1448
1449The help text reveals that the return type needs a generic lifetime parameter
1450on it because Rust can’t tell whether the reference being returned refers to
1451`x` or `y`. Actually, we don’t know either, because the `if` block in the body
1452of this function returns a reference to `x` and the `else` block returns a
1453reference to `y`!
1454
1455When we’re defining this function, we don’t know the concrete values that will
1456be passed into this function, so we don’t know whether the `if` case or the
1457`else` case will execute. We also don’t know the concrete lifetimes of the
1458references that will be passed in, so we can’t look at the scopes as we did in
923072b8 1459Listings 10-17 and 10-18 to determine whether the reference we return will
3c0e092e
XL
1460always be valid. The borrow checker can’t determine this either, because it
1461doesn’t know how the lifetimes of `x` and `y` relate to the lifetime of the
1462return value. To fix this error, we’ll add generic lifetime parameters that
1463define the relationship between the references so the borrow checker can
1464perform its analysis.
1465
1466### Lifetime Annotation Syntax
1467
5e7ed085
FG
1468Lifetime annotations don’t change how long any of the references live. Rather,
1469they describe the relationships of the lifetimes of multiple references to each
1470other without affecting the lifetimes. Just as functions can accept any type
1471when the signature specifies a generic type parameter, functions can accept
1472references with any lifetime by specifying a generic lifetime parameter.
3c0e092e
XL
1473
1474Lifetime annotations have a slightly unusual syntax: the names of lifetime
5e7ed085
FG
1475parameters must start with an apostrophe (`'`) and are usually all lowercase
1476and very short, like generic types. Most people use the name `'a` for the first
1477lifetime annotation. We place lifetime parameter annotations after the `&` of a
1478reference, using a space to separate the annotation from the reference’s type.
3c0e092e
XL
1479
1480Here are some examples: a reference to an `i32` without a lifetime parameter, a
1481reference to an `i32` that has a lifetime parameter named `'a`, and a mutable
1482reference to an `i32` that also has the lifetime `'a`.
1483
1484```
1485&i32 // a reference
1486&'a i32 // a reference with an explicit lifetime
1487&'a mut i32 // a mutable reference with an explicit lifetime
1488```
1489
1490One lifetime annotation by itself doesn’t have much meaning, because the
1491annotations are meant to tell Rust how generic lifetime parameters of multiple
923072b8
FG
1492references relate to each other. Let’s examine how the lifetime annotations
1493relate to each other in the context of the `longest` function.
1494
1495<!---
1496
1497The above description is a little hard to follow with a code example.
1498
1499/JT --->
1500<!-- Rather than fleshing out the code that goes with this description, I've
1501moved some of the description to the next section to go with the code example
1502there. /Carol -->
3c0e092e
XL
1503
1504### Lifetime Annotations in Function Signatures
1505
923072b8
FG
1506To use lifetime annotations in function signatures, we need to declare the
1507generic *lifetime* parameters inside angle brackets between the function name
1508and the parameter list, just as we did with generic *type* parameters
1509
1510We want the signature to express the following constraint: the returned
5e7ed085
FG
1511reference will be valid as long as both the parameters are valid. This is the
1512relationship between lifetimes of the parameters and the return value. We’ll
1513name the lifetime `'a` and then add it to each reference, as shown in Listing
923072b8 151410-21.
3c0e092e
XL
1515
1516Filename: src/main.rs
1517
1518```
1519fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
1520 if x.len() > y.len() {
1521 x
1522 } else {
1523 y
1524 }
1525}
1526```
1527
923072b8 1528Listing 10-21: The `longest` function definition specifying that all the
3c0e092e
XL
1529references in the signature must have the same lifetime `'a`
1530
1531This code should compile and produce the result we want when we use it with the
923072b8 1532`main` function in Listing 10-19.
3c0e092e
XL
1533
1534The function signature now tells Rust that for some lifetime `'a`, the function
1535takes two parameters, both of which are string slices that live at least as
1536long as lifetime `'a`. The function signature also tells Rust that the string
1537slice returned from the function will live at least as long as lifetime `'a`.
1538In practice, it means that the lifetime of the reference returned by the
923072b8
FG
1539`longest` function is the same as the smaller of the lifetimes of the values
1540referred to by the function arguments. These relationships are what we want
1541Rust to use when analyzing this code.
3c0e092e
XL
1542
1543Remember, when we specify the lifetime parameters in this function signature,
1544we’re not changing the lifetimes of any values passed in or returned. Rather,
1545we’re specifying that the borrow checker should reject any values that don’t
1546adhere to these constraints. Note that the `longest` function doesn’t need to
1547know exactly how long `x` and `y` will live, only that some scope can be
1548substituted for `'a` that will satisfy this signature.
1549
1550When annotating lifetimes in functions, the annotations go in the function
1551signature, not in the function body. The lifetime annotations become part of
5e7ed085 1552the contract of the function, much like the types in the signature. Having
3c0e092e
XL
1553function signatures contain the lifetime contract means the analysis the Rust
1554compiler does can be simpler. If there’s a problem with the way a function is
1555annotated or the way it is called, the compiler errors can point to the part of
1556our code and the constraints more precisely. If, instead, the Rust compiler
1557made more inferences about what we intended the relationships of the lifetimes
1558to be, the compiler might only be able to point to a use of our code many steps
1559away from the cause of the problem.
1560
1561When we pass concrete references to `longest`, the concrete lifetime that is
1562substituted for `'a` is the part of the scope of `x` that overlaps with the
1563scope of `y`. In other words, the generic lifetime `'a` will get the concrete
1564lifetime that is equal to the smaller of the lifetimes of `x` and `y`. Because
1565we’ve annotated the returned reference with the same lifetime parameter `'a`,
1566the returned reference will also be valid for the length of the smaller of the
1567lifetimes of `x` and `y`.
1568
1569Let’s look at how the lifetime annotations restrict the `longest` function by
923072b8 1570passing in references that have different concrete lifetimes. Listing 10-22 is
3c0e092e
XL
1571a straightforward example.
1572
1573Filename: src/main.rs
1574
1575```
1576fn main() {
1577 let string1 = String::from("long string is long");
1578
1579 {
1580 let string2 = String::from("xyz");
1581 let result = longest(string1.as_str(), string2.as_str());
1582 println!("The longest string is {}", result);
1583 }
1584}
1585```
1586
923072b8 1587Listing 10-22: Using the `longest` function with references to `String` values
3c0e092e
XL
1588that have different concrete lifetimes
1589
1590In this example, `string1` is valid until the end of the outer scope, `string2`
1591is valid until the end of the inner scope, and `result` references something
1592that is valid until the end of the inner scope. Run this code, and you’ll see
5e7ed085
FG
1593that the borrow checker approves; it will compile and print `The longest string
1594is long string is long`.
3c0e092e
XL
1595
1596Next, let’s try an example that shows that the lifetime of the reference in
1597`result` must be the smaller lifetime of the two arguments. We’ll move the
1598declaration of the `result` variable outside the inner scope but leave the
1599assignment of the value to the `result` variable inside the scope with
5e7ed085 1600`string2`. Then we’ll move the `println!` that uses `result` to outside the
923072b8 1601inner scope, after the inner scope has ended. The code in Listing 10-23 will
5e7ed085 1602not compile.
3c0e092e
XL
1603
1604Filename: src/main.rs
1605
1606```
1607fn main() {
1608 let string1 = String::from("long string is long");
1609 let result;
1610 {
1611 let string2 = String::from("xyz");
1612 result = longest(string1.as_str(), string2.as_str());
1613 }
1614 println!("The longest string is {}", result);
1615}
1616```
1617
923072b8 1618Listing 10-23: Attempting to use `result` after `string2` has gone out of scope
3c0e092e 1619
5e7ed085 1620When we try to compile this code, we get this error:
3c0e092e
XL
1621
1622```
1623error[E0597]: `string2` does not live long enough
1624 --> src/main.rs:6:44
1625 |
16266 | result = longest(string1.as_str(), string2.as_str());
1627 | ^^^^^^^ borrowed value does not live long enough
16287 | }
1629 | - `string2` dropped here while still borrowed
16308 | println!("The longest string is {}", result);
1631 | ------ borrow later used here
1632```
1633
1634The error shows that for `result` to be valid for the `println!` statement,
1635`string2` would need to be valid until the end of the outer scope. Rust knows
1636this because we annotated the lifetimes of the function parameters and return
1637values using the same lifetime parameter `'a`.
1638
1639As humans, we can look at this code and see that `string1` is longer than
1640`string2` and therefore `result` will contain a reference to `string1`.
1641Because `string1` has not gone out of scope yet, a reference to `string1` will
1642still be valid for the `println!` statement. However, the compiler can’t see
1643that the reference is valid in this case. We’ve told Rust that the lifetime of
1644the reference returned by the `longest` function is the same as the smaller of
1645the lifetimes of the references passed in. Therefore, the borrow checker
923072b8 1646disallows the code in Listing 10-23 as possibly having an invalid reference.
3c0e092e
XL
1647
1648Try designing more experiments that vary the values and lifetimes of the
1649references passed in to the `longest` function and how the returned reference
1650is used. Make hypotheses about whether or not your experiments will pass the
1651borrow checker before you compile; then check to see if you’re right!
1652
1653### Thinking in Terms of Lifetimes
1654
1655The way in which you need to specify lifetime parameters depends on what your
1656function is doing. For example, if we changed the implementation of the
1657`longest` function to always return the first parameter rather than the longest
1658string slice, we wouldn’t need to specify a lifetime on the `y` parameter. The
1659following code will compile:
1660
1661Filename: src/main.rs
1662
1663```
1664fn longest<'a>(x: &'a str, y: &str) -> &'a str {
1665 x
1666}
1667```
1668
5e7ed085
FG
1669We’ve specified a lifetime parameter `'a` for the parameter `x` and the return
1670type, but not for the parameter `y`, because the lifetime of `y` does not have
1671any relationship with the lifetime of `x` or the return value.
3c0e092e
XL
1672
1673When returning a reference from a function, the lifetime parameter for the
1674return type needs to match the lifetime parameter for one of the parameters. If
1675the reference returned does *not* refer to one of the parameters, it must refer
5e7ed085
FG
1676to a value created within this function. However, this would be a dangling
1677reference because the value will go out of scope at the end of the function.
1678Consider this attempted implementation of the `longest` function that won’t
1679compile:
3c0e092e
XL
1680
1681Filename: src/main.rs
1682
1683```
1684fn longest<'a>(x: &str, y: &str) -> &'a str {
1685 let result = String::from("really long string");
1686 result.as_str()
1687}
1688```
1689
1690Here, even though we’ve specified a lifetime parameter `'a` for the return
1691type, this implementation will fail to compile because the return value
1692lifetime is not related to the lifetime of the parameters at all. Here is the
1693error message we get:
1694
1695```
1696error[E0515]: cannot return value referencing local variable `result`
1697 --> src/main.rs:11:5
1698 |
169911 | result.as_str()
1700 | ------^^^^^^^^^
1701 | |
1702 | returns a value referencing data owned by the current function
1703 | `result` is borrowed here
1704```
1705
1706The problem is that `result` goes out of scope and gets cleaned up at the end
1707of the `longest` function. We’re also trying to return a reference to `result`
1708from the function. There is no way we can specify lifetime parameters that
1709would change the dangling reference, and Rust won’t let us create a dangling
1710reference. In this case, the best fix would be to return an owned data type
1711rather than a reference so the calling function is then responsible for
1712cleaning up the value.
1713
1714Ultimately, lifetime syntax is about connecting the lifetimes of various
1715parameters and return values of functions. Once they’re connected, Rust has
1716enough information to allow memory-safe operations and disallow operations that
1717would create dangling pointers or otherwise violate memory safety.
1718
1719### Lifetime Annotations in Struct Definitions
1720
923072b8 1721So far, the structs we’ve defined all hold owned types. We can define structs to
5e7ed085 1722hold references, but in that case we would need to add a lifetime annotation on
923072b8 1723every reference in the struct’s definition. Listing 10-24 has a struct named
5e7ed085 1724`ImportantExcerpt` that holds a string slice.
3c0e092e 1725
923072b8
FG
1726<!---
1727
1728nit: "So far, the structs we've *defined* all hold owned types"
1729
1730/JT --->
1731<!-- Fixed! /Carol -->
1732
3c0e092e
XL
1733Filename: src/main.rs
1734
1735```
1736struct ImportantExcerpt<'a> {
1737 part: &'a str,
1738}
1739
1740fn main() {
1741 let novel = String::from("Call me Ishmael. Some years ago...");
1742 let first_sentence = novel.split('.').next().expect("Could not find a '.'");
1743 let i = ImportantExcerpt {
1744 part: first_sentence,
1745 };
1746}
1747```
1748
923072b8 1749Listing 10-24: A struct that holds a reference, requiring a lifetime annotation
3c0e092e 1750
5e7ed085 1751This struct has the single field `part` that holds a string slice, which is a
3c0e092e
XL
1752reference. As with generic data types, we declare the name of the generic
1753lifetime parameter inside angle brackets after the name of the struct so we can
1754use the lifetime parameter in the body of the struct definition. This
1755annotation means an instance of `ImportantExcerpt` can’t outlive the reference
1756it holds in its `part` field.
1757
1758The `main` function here creates an instance of the `ImportantExcerpt` struct
1759that holds a reference to the first sentence of the `String` owned by the
1760variable `novel`. The data in `novel` exists before the `ImportantExcerpt`
1761instance is created. In addition, `novel` doesn’t go out of scope until after
1762the `ImportantExcerpt` goes out of scope, so the reference in the
1763`ImportantExcerpt` instance is valid.
1764
1765### Lifetime Elision
1766
1767You’ve learned that every reference has a lifetime and that you need to specify
1768lifetime parameters for functions or structs that use references. However, in
923072b8 1769Chapter 4 we had a function in Listing 4-9, shown again in Listing 10-25, that
5e7ed085 1770compiled without lifetime annotations.
3c0e092e
XL
1771
1772Filename: src/lib.rs
1773
1774```
1775fn first_word(s: &str) -> &str {
1776 let bytes = s.as_bytes();
1777
1778 for (i, &item) in bytes.iter().enumerate() {
1779 if item == b' ' {
1780 return &s[0..i];
1781 }
1782 }
1783
1784 &s[..]
1785}
1786```
1787
923072b8 1788Listing 10-25: A function we defined in Listing 4-9 that compiled without
3c0e092e
XL
1789lifetime annotations, even though the parameter and return type are references
1790
1791The reason this function compiles without lifetime annotations is historical:
1792in early versions (pre-1.0) of Rust, this code wouldn’t have compiled because
1793every reference needed an explicit lifetime. At that time, the function
1794signature would have been written like this:
1795
1796```
1797fn first_word<'a>(s: &'a str) -> &'a str {
1798```
1799
1800After writing a lot of Rust code, the Rust team found that Rust programmers
1801were entering the same lifetime annotations over and over in particular
1802situations. These situations were predictable and followed a few deterministic
1803patterns. The developers programmed these patterns into the compiler’s code so
1804the borrow checker could infer the lifetimes in these situations and wouldn’t
1805need explicit annotations.
1806
1807This piece of Rust history is relevant because it’s possible that more
1808deterministic patterns will emerge and be added to the compiler. In the future,
1809even fewer lifetime annotations might be required.
1810
1811The patterns programmed into Rust’s analysis of references are called the
1812*lifetime elision rules*. These aren’t rules for programmers to follow; they’re
1813a set of particular cases that the compiler will consider, and if your code
1814fits these cases, you don’t need to write the lifetimes explicitly.
1815
1816The elision rules don’t provide full inference. If Rust deterministically
1817applies the rules but there is still ambiguity as to what lifetimes the
1818references have, the compiler won’t guess what the lifetime of the remaining
5e7ed085
FG
1819references should be. Instead of guessing, the compiler will give you an error
1820that you can resolve by adding the lifetime annotations.
3c0e092e
XL
1821
1822Lifetimes on function or method parameters are called *input lifetimes*, and
1823lifetimes on return values are called *output lifetimes*.
1824
5e7ed085
FG
1825The compiler uses three rules to figure out the lifetimes of the references
1826when there aren’t explicit annotations. The first rule applies to input
1827lifetimes, and the second and third rules apply to output lifetimes. If the
1828compiler gets to the end of the three rules and there are still references for
1829which it can’t figure out lifetimes, the compiler will stop with an error.
1830These rules apply to `fn` definitions as well as `impl` blocks.
3c0e092e 1831
5e7ed085 1832The first rule is that the compiler assigns a lifetime parameter to each
923072b8 1833parameter that’s a reference. In other words, a function with one parameter gets
5e7ed085
FG
1834one lifetime parameter: `fn foo<'a>(x: &'a i32)`; a function with two
1835parameters gets two separate lifetime parameters: `fn foo<'a, 'b>(x: &'a i32,
1836y: &'b i32)`; and so on.
3c0e092e 1837
5e7ed085 1838The second rule is that, if there is exactly one input lifetime parameter, that
3c0e092e
XL
1839lifetime is assigned to all output lifetime parameters: `fn foo<'a>(x: &'a i32)
1840-> &'a i32`.
1841
5e7ed085
FG
1842The third rule is that, if there are multiple input lifetime parameters, but
1843one of them is `&self` or `&mut self` because this is a method, the lifetime of
1844`self` is assigned to all output lifetime parameters. This third rule makes
1845methods much nicer to read and write because fewer symbols are necessary.
3c0e092e 1846
5e7ed085
FG
1847Let’s pretend we’re the compiler. We’ll apply these rules to figure out the
1848lifetimes of the references in the signature of the `first_word` function in
923072b8 1849Listing 10-25. The signature starts without any lifetimes associated with the
5e7ed085 1850references:
3c0e092e
XL
1851
1852```
1853fn first_word(s: &str) -> &str {
1854```
1855
1856Then the compiler applies the first rule, which specifies that each parameter
1857gets its own lifetime. We’ll call it `'a` as usual, so now the signature is
1858this:
1859
1860```
1861fn first_word<'a>(s: &'a str) -> &str {
1862```
1863
1864The second rule applies because there is exactly one input lifetime. The second
1865rule specifies that the lifetime of the one input parameter gets assigned to
1866the output lifetime, so the signature is now this:
1867
1868```
1869fn first_word<'a>(s: &'a str) -> &'a str {
1870```
1871
1872Now all the references in this function signature have lifetimes, and the
1873compiler can continue its analysis without needing the programmer to annotate
1874the lifetimes in this function signature.
1875
1876Let’s look at another example, this time using the `longest` function that had
923072b8 1877no lifetime parameters when we started working with it in Listing 10-20:
3c0e092e
XL
1878
1879```
1880fn longest(x: &str, y: &str) -> &str {
1881```
1882
1883Let’s apply the first rule: each parameter gets its own lifetime. This time we
1884have two parameters instead of one, so we have two lifetimes:
1885
1886```
1887fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {
1888```
1889
1890You can see that the second rule doesn’t apply because there is more than one
1891input lifetime. The third rule doesn’t apply either, because `longest` is a
1892function rather than a method, so none of the parameters are `self`. After
1893working through all three rules, we still haven’t figured out what the return
1894type’s lifetime is. This is why we got an error trying to compile the code in
923072b8 1895Listing 10-20: the compiler worked through the lifetime elision rules but still
3c0e092e
XL
1896couldn’t figure out all the lifetimes of the references in the signature.
1897
1898Because the third rule really only applies in method signatures, we’ll look at
1899lifetimes in that context next to see why the third rule means we don’t have to
1900annotate lifetimes in method signatures very often.
1901
1902### Lifetime Annotations in Method Definitions
1903
1904When we implement methods on a struct with lifetimes, we use the same syntax as
1905that of generic type parameters shown in Listing 10-11. Where we declare and
1906use the lifetime parameters depends on whether they’re related to the struct
1907fields or the method parameters and return values.
1908
1909Lifetime names for struct fields always need to be declared after the `impl`
1910keyword and then used after the struct’s name, because those lifetimes are part
1911of the struct’s type.
1912
1913In method signatures inside the `impl` block, references might be tied to the
1914lifetime of references in the struct’s fields, or they might be independent. In
1915addition, the lifetime elision rules often make it so that lifetime annotations
1916aren’t necessary in method signatures. Let’s look at some examples using the
923072b8 1917struct named `ImportantExcerpt` that we defined in Listing 10-24.
3c0e092e
XL
1918
1919First, we’ll use a method named `level` whose only parameter is a reference to
1920`self` and whose return value is an `i32`, which is not a reference to anything:
1921
1922```
1923impl<'a> ImportantExcerpt<'a> {
1924 fn level(&self) -> i32 {
1925 3
1926 }
1927}
1928```
1929
1930The lifetime parameter declaration after `impl` and its use after the type name
1931are required, but we’re not required to annotate the lifetime of the reference
1932to `self` because of the first elision rule.
1933
1934Here is an example where the third lifetime elision rule applies:
1935
1936```
1937impl<'a> ImportantExcerpt<'a> {
1938 fn announce_and_return_part(&self, announcement: &str) -> &str {
1939 println!("Attention please: {}", announcement);
1940 self.part
1941 }
1942}
1943```
1944
1945There are two input lifetimes, so Rust applies the first lifetime elision rule
1946and gives both `&self` and `announcement` their own lifetimes. Then, because
1947one of the parameters is `&self`, the return type gets the lifetime of `&self`,
1948and all lifetimes have been accounted for.
1949
1950### The Static Lifetime
1951
5e7ed085
FG
1952One special lifetime we need to discuss is `'static`, which denotes that the
1953affected reference *can* live for the entire duration of the program. All
1954string literals have the `'static` lifetime, which we can annotate as follows:
3c0e092e
XL
1955
1956```
1957let s: &'static str = "I have a static lifetime.";
1958```
1959
1960The text of this string is stored directly in the program’s binary, which
1961is always available. Therefore, the lifetime of all string literals is
1962`'static`.
1963
1964You might see suggestions to use the `'static` lifetime in error messages. But
1965before specifying `'static` as the lifetime for a reference, think about
1966whether the reference you have actually lives the entire lifetime of your
5e7ed085 1967program or not, and whether you want it to. Most of the time, an error message
923072b8
FG
1968suggesting the `'static` lifetime results from attempting to create a dangling
1969reference or a mismatch of the available lifetimes. In such cases, the solution
1970is fixing those problems, not specifying the `'static` lifetime.
3c0e092e
XL
1971
1972## Generic Type Parameters, Trait Bounds, and Lifetimes Together
1973
1974Let’s briefly look at the syntax of specifying generic type parameters, trait
1975bounds, and lifetimes all in one function!
1976
1977```
1978use std::fmt::Display;
1979
1980fn longest_with_an_announcement<'a, T>(
1981 x: &'a str,
1982 y: &'a str,
1983 ann: T,
1984) -> &'a str
1985where
1986 T: Display,
1987{
1988 println!("Announcement! {}", ann);
1989 if x.len() > y.len() {
1990 x
1991 } else {
1992 y
1993 }
1994}
1995```
1996
923072b8 1997This is the `longest` function from Listing 10-21 that returns the longer of
3c0e092e
XL
1998two string slices. But now it has an extra parameter named `ann` of the generic
1999type `T`, which can be filled in by any type that implements the `Display`
2000trait as specified by the `where` clause. This extra parameter will be printed
2001using `{}`, which is why the `Display` trait bound is necessary. Because
2002lifetimes are a type of generic, the declarations of the lifetime parameter
2003`'a` and the generic type parameter `T` go in the same list inside the angle
2004brackets after the function name.
2005
2006## Summary
2007
2008We covered a lot in this chapter! Now that you know about generic type
2009parameters, traits and trait bounds, and generic lifetime parameters, you’re
2010ready to write code without repetition that works in many different situations.
2011Generic type parameters let you apply the code to different types. Traits and
2012trait bounds ensure that even though the types are generic, they’ll have the
2013behavior the code needs. You learned how to use lifetime annotations to ensure
2014that this flexible code won’t have any dangling references. And all of this
2015analysis happens at compile time, which doesn’t affect runtime performance!
2016
2017Believe it or not, there is much more to learn on the topics we discussed in
2018this chapter: Chapter 17 discusses trait objects, which are another way to use
2019traits. There are also more complex scenarios involving lifetime annotations
2020that you will only need in very advanced scenarios; for those, you should read
2021the Rust Reference at *https://doc.rust-lang.org/reference/trait-bounds.html*.
2022But next, you’ll learn how to write tests in Rust so you can make sure your
2023code is working the way it should.