4 # Generic Types, Traits, and Lifetimes
6 Every programming language has tools to deal effectively with duplication of
7 concepts; in Rust, one of those tools is *generics*. Generics are abstract
8 stand-ins for concrete types or other properties. We can express properties of
9 generics, such as their behavior or how they relate to other generics, without
10 needing to know when we’re writing and compiling the code what will actually be
13 In the same way that a function takes parameters whose value we don’t know in
14 order to write code once that will be run on multiple concrete values, we can
15 write functions that take parameters of some generic type instead of a concrete
16 type like `i32` or `String`. We’ve already used generics in Chapter 6 with
17 `Option<T>`, Chapter 8 with `Vec<T>` and `HashMap<K, V>`, and Chapter 9 with
18 `Result<T, E>`. In this chapter, we’ll explore how to define our own types,
19 functions, and methods with generics!
21 First, we’re going to review the mechanics of extracting a function that
22 reduces code duplication. Then we’ll use the same mechanics to make a generic
23 function out of two functions that only differ in the types of their
24 parameters. We’ll go over using generic types in struct and enum definitions
27 After that, we’ll discuss *traits*, which are a way to define behavior in a
28 generic way. Traits can be combined with generic types in order to constrain a
29 generic type to those types that have a particular behavior, rather than any
32 Finally, we’ll discuss *lifetimes*, which are a kind of generic that let us
33 give the compiler information about how references are related to each other.
34 Lifetimes are the feature in Rust that allow us to borrow values in many
35 situations and still have the compiler check that references will be valid.
37 ## Removing Duplication by Extracting a Function
39 Before getting into generics syntax, let’s first review a technique for dealing
40 with duplication that doesn’t use generic types: extracting a function. Once
41 that’s fresh in our minds, we’ll use the same mechanics with generics to
42 extract a generic function! In the same way that you recognize duplicated code
43 to extract into a function, you’ll start to recognize duplicated code that can
46 Consider a small program that finds the largest number in a list, shown in
53 let numbers = vec![34, 50, 25, 100, 65];
55 let mut largest = numbers[0];
57 for number in numbers {
63 println!("The largest number is {}", largest);
67 Listing 10-1: Code to find the largest number in a list of numbers
69 This code takes a list of integers, stored here in the variable `numbers`. It
70 puts the first item in the list in a variable named `largest`. Then it iterates
71 through all the numbers in the list, and if the current value is greater than
72 the number stored in `largest`, it replaces the value in `largest`. If the
73 current value is smaller than the largest value seen so far, `largest` is not
74 changed. When all the items in the list have been considered, `largest` will
75 hold the largest value, which in this case is 100.
77 If we needed to find the largest number in two different lists of numbers, we
78 could duplicate the code in Listing 10-1 and have the same logic exist in two
79 places in the program, as in Listing 10-2:
85 let numbers = vec![34, 50, 25, 100, 65];
87 let mut largest = numbers[0];
89 for number in numbers {
95 println!("The largest number is {}", largest);
97 let numbers = vec![102, 34, 6000, 89, 54, 2, 43, 8];
99 let mut largest = numbers[0];
101 for number in numbers {
102 if number > largest {
107 println!("The largest number is {}", largest);
111 Listing 10-2: Code to find the largest number in *two* lists of numbers
113 While this code works, duplicating code is tedious and error-prone, and means
114 we have multiple places to update the logic if we need to change it.
116 <!-- Are we safe assuming the reader will be familiar with the term
117 "abstraction" in this context, or do we want to give a brief definition? -->
118 <!-- Yes, our audience will be familiar with this term. /Carol -->
120 To eliminate this duplication, we can create an abstraction, which in this case
121 will be in the form of a function that operates on any list of integers given
122 to the function in a parameter. This will increase the clarity of our code and
123 let us communicate and reason about the concept of finding the largest number
124 in a list independently of the specific places this concept is used.
126 In the program in Listing 10-3, we’ve extracted the code that finds the largest
127 number into a function named `largest`. This program can find the largest
128 number in two different lists of numbers, but the code from Listing 10-1 only
131 Filename: src/main.rs
134 fn largest(list: &[i32]) -> i32 {
135 let mut largest = list[0];
137 for &item in list.iter() {
147 let numbers = vec![34, 50, 25, 100, 65];
149 let result = largest(&numbers);
150 println!("The largest number is {}", result);
152 let numbers = vec![102, 34, 6000, 89, 54, 2, 43, 8];
154 let result = largest(&numbers);
155 println!("The largest number is {}", result);
159 Listing 10-3: Abstracted code to find the largest number in two lists
161 The function has a parameter, `list`, which represents any concrete slice of
162 `i32` values that we might pass into the function. The code in the function
163 definition operates on the `list` representation of any `&[i32]`. When we call
164 the `largest` function, the code actually runs on the specific values that we
167 The mechanics we went through to get from Listing 10-2 to Listing 10-3 were
170 1. We noticed there was duplicate code.
171 2. We extracted the duplicate code into the body of the function, and specified
172 the inputs and return values of that code in the function signature.
173 3. We replaced the two concrete places that had the duplicated code to call the
176 We can use these same steps with generics to reduce code duplication in
177 different ways in different scenarios. In the same way that the function body
178 is now operating on an abstract `list` instead of concrete values, code using
179 generics will operate on abstract types. The concepts powering generics are the
180 same concepts you already know that power functions, just applied in different
183 What if we had two functions, one that found the largest item in a slice of
184 `i32` values and one that found the largest item in a slice of `char` values?
185 How would we get rid of that duplication? Let’s find out!
187 ## Generic Data Types
189 Using generics where we usually place types, like in function signatures or
190 structs, lets us create definitions that we can use for many different concrete
191 data types. Let’s take a look at how to define functions, structs, enums, and
192 methods using generics, and at the end of this section we’ll discuss the
193 performance of code using generics.
195 ### Using Generic Data Types in Function Definitions
197 We can define functions that use generics in the signature of the function
198 where the data types of the parameters and return value go. In this way, the
199 code we write can be more flexible and provide more functionality to callers of
200 our function, while not introducing code duplication.
202 Continuing with our `largest` function, Listing 10-4 shows two functions
203 providing the same functionality to find the largest value in a slice. The
204 first function is the one we extracted in Listing 10-3 that finds the largest
205 `i32` in a slice. The second function finds the largest `char` in a slice:
207 Filename: src/main.rs
210 fn largest_i32(list: &[i32]) -> i32 {
211 let mut largest = list[0];
213 for &item in list.iter() {
222 fn largest_char(list: &[char]) -> char {
223 let mut largest = list[0];
225 for &item in list.iter() {
235 let numbers = vec![34, 50, 25, 100, 65];
237 let result = largest_i32(&numbers);
238 println!("The largest number is {}", result);
240 let chars = vec!['y', 'm', 'a', 'q'];
242 let result = largest_char(&chars);
243 println!("The largest char is {}", result);
247 Listing 10-4: Two functions that differ only in their names and the types in
250 Here, the functions `largest_i32` and `largest_char` have the exact same body,
251 so it would be nice if we could turn these two functions into one and get rid
252 of the duplication. Luckily, we can do that by introducing a generic type
255 To parameterize the types in the signature of the one function we’re going to
256 define, we need to create a name for the type parameter, just like how we give
257 names for the value parameters to a function. We’re going to choose the name
258 `T`. Any identifier can be used as a type parameter name, but we’re choosing
259 `T` because Rust’s type naming convention is CamelCase. Generic type parameter
260 names also tend to be short by convention, often just one letter. Short for
261 “type”, `T` is the default choice of most Rust programmers.
263 When we use a parameter in the body of the function, we have to declare the
264 parameter in the signature so that the compiler knows what that name in the
265 body means. Similarly, when we use a type parameter name in a function
266 signature, we have to declare the type parameter name before we use it. Type
267 name declarations go in angle brackets between the name of the function and the
270 The function signature of the generic `largest` function we’re going to define
274 fn largest<T>(list: &[T]) -> T {
277 We would read this as: the function `largest` is generic over some type `T`. It
278 has one parameter named `list`, and the type of `list` is a slice of values of
279 type `T`. The `largest` function will return a value of the same type `T`.
281 Listing 10-5 shows the unified `largest` function definition using the generic
282 data type in its signature, and shows how we’ll be able to call `largest` with
283 either a slice of `i32` values or `char` values. Note that this code won’t
286 Filename: src/main.rs
289 fn largest<T>(list: &[T]) -> T {
290 let mut largest = list[0];
292 for &item in list.iter() {
302 let numbers = vec![34, 50, 25, 100, 65];
304 let result = largest(&numbers);
305 println!("The largest number is {}", result);
307 let chars = vec!['y', 'm', 'a', 'q'];
309 let result = largest(&chars);
310 println!("The largest char is {}", result);
314 Listing 10-5: A definition of the `largest` function that uses generic type
315 parameters but doesn’t compile yet
317 If we try to compile this code right now, we’ll get this error:
320 error[E0369]: binary operation `>` cannot be applied to type `T`
322 5 | if item > largest {
325 note: an implementation of `std::cmp::PartialOrd` might be missing for `T`
328 The note mentions `std::cmp::PartialOrd`, which is a *trait*. We’re going to
329 talk about traits in the next section, but briefly, what this error is saying
330 is that the body of `largest` won’t work for all possible types that `T` could
331 be; since we want to compare values of type `T` in the body, we can only use
332 types that know how to be ordered. The standard library has defined the trait
333 `std::cmp::PartialOrd` that types can implement to enable comparisons. We’ll
334 come back to traits and how to specify that a generic type has a particular
335 trait in the next section, but let’s set this example aside for a moment and
336 explore other places we can use generic type parameters first.
338 <!-- Liz: this is the reason we had the topics in the order we did in the first
339 draft of this chapter; it's hard to do anything interesting with generic types
340 in functions unless you also know about traits and trait bounds. I think this
341 ordering could work out okay, though, and keep a stronger thread with the
342 `longest` function going through the whole chapter, but we do pause with a
343 not-yet-compiling example here, which I know isn't ideal either. Let us know
344 what you think. /Carol -->
346 ### Using Generic Data Types in Struct Definitions
348 We can define structs to use a generic type parameter in one or more of the
349 struct’s fields with the `<>` syntax too. Listing 10-6 shows the definition and
350 use of a `Point` struct that can hold `x` and `y` coordinate values of any type:
352 Filename: src/main.rs
361 let integer = Point { x: 5, y: 10 };
362 let float = Point { x: 1.0, y: 4.0 };
366 Listing 10-6: A `Point` struct that holds `x` and `y` values of type `T`
368 The syntax is similar to using generics in function definitions. First, we have
369 to declare the name of the type parameter within angle brackets just after the
370 name of the struct. Then we can use the generic type in the struct definition
371 where we would specify concrete data types.
373 Note that because we’ve only used one generic type in the definition of
374 `Point`, what we’re saying is that the `Point` struct is generic over some type
375 `T`, and the fields `x` and `y` are *both* that same type, whatever it ends up
376 being. If we try to create an instance of a `Point` that has values of
377 different types, as in Listing 10-7, our code won’t compile:
379 Filename: src/main.rs
388 let wont_work = Point { x: 5, y: 4.0 };
392 Listing 10-7: The fields `x` and `y` must be the same type because both have
393 the same generic data type `T`
395 If we try to compile this, we’ll get the following error:
398 error[E0308]: mismatched types
401 7 | let wont_work = Point { x: 5, y: 4.0 };
402 | ^^^ expected integral variable, found
403 floating-point variable
405 = note: expected type `{integer}`
406 = note: found type `{float}`
409 When we assigned the integer value 5 to `x`, the compiler then knows for this
410 instance of `Point` that the generic type `T` will be an integer. Then when we
411 specified 4.0 for `y`, which is defined to have the same type as `x`, we get a
414 If we wanted to define a `Point` struct where `x` and `y` could have different
415 types but still have those types be generic, we can use multiple generic type
416 parameters. In listing 10-8, we’ve changed the definition of `Point` to be
417 generic over types `T` and `U`. The field `x` is of type `T`, and the field `y`
420 Filename: src/main.rs
429 let both_integer = Point { x: 5, y: 10 };
430 let both_float = Point { x: 1.0, y: 4.0 };
431 let integer_and_float = Point { x: 5, y: 4.0 };
435 Listing 10-8: A `Point` generic over two types so that `x` and `y` may be
436 values of different types
438 Now all of these instances of `Point` are allowed! You can use as many generic
439 type parameters in a definition as you want, but using more than a few gets
440 hard to read and understand. If you get to a point of needing lots of generic
441 types, it’s probably a sign that your code could use some restructuring to be
442 separated into smaller pieces.
444 ### Using Generic Data Types in Enum Definitions
446 Similarly to structs, enums can be defined to hold generic data types in their
447 variants. We used the `Option<T>` enum provided by the standard library in
448 Chapter 6, and now its definition should make more sense. Let’s take another
458 In other words, `Option<T>` is an enum generic in type `T`. It has two
459 variants: `Some`, which holds one value of type `T`, and a `None` variant that
460 doesn’t hold any value. The standard library only has to have this one
461 definition to support the creation of values of this enum that have any
462 concrete type. The idea of “an optional value” is a more abstract concept than
463 one specific type, and Rust lets us express this abstract concept without lots
466 Enums can use multiple generic types as well. The definition of the `Result`
467 enum that we used in Chapter 9 is one example:
476 The `Result` enum is generic over two types, `T` and `E`. `Result` has two
477 variants: `Ok`, which holds a value of type `T`, and `Err`, which holds a value
478 of type `E`. This definition makes it convenient to use the `Result` enum
479 anywhere we have an operation that might succeed (and return a value of some
480 type `T`) or fail (and return an error of some type `E`). Recall Listing 9-2
481 when we opened a file: in that case, `T` was filled in with the type
482 `std::fs::File` when the file was opened successfully and `E` was filled in
483 with the type `std::io::Error` when there were problems opening the file.
485 When you recognize situations in your code with multiple struct or enum
486 definitions that differ only in the types of the values they hold, you can
487 remove the duplication by using the same process we used with the function
488 definitions to introduce generic types instead.
490 ### Using Generic Data Types in Method Definitions
492 Like we did in Chapter 5, we can implement methods on structs and enums that
493 have generic types in their definitions. Listing 10-9 shows the `Point<T>`
494 struct we defined in Listing 10-6. We’ve then defined a method named `x` on
495 `Point<T>` that returns a reference to the data in the field `x`:
497 Filename: src/main.rs
512 let p = Point { x: 5, y: 10 };
514 println!("p.x = {}", p.x());
518 Listing 10-9: Implementing a method named `x` on the `Point<T>` struct that
519 will return a reference to the `x` field, which is of type `T`.
521 Note that we have to declare `T` just after `impl`, so that we can use it when
522 we specify that we’re implementing methods on the type `Point<T>`.
524 Generic type parameters in a struct definition aren’t always the same generic
525 type parameters you want to use in that struct’s method signatures. Listing
526 10-10 defines a method `mixup` on the `Point<T, U>` struct from Listing 10-8.
527 The method takes another `Point` as a parameter, which might have different
528 types than the `self` `Point` that we’re calling `mixup` on. The method creates
529 a new `Point` instance that has the `x` value from the `self` `Point` (which is
530 of type `T`) and the `y` value from the passed-in `Point` (which is of type
533 Filename: src/main.rs
541 impl<T, U> Point<T, U> {
542 fn mixup<V, W>(&self, other: &Point<V, W>) -> Point<T, W> {
551 let p1 = Point { x: 5, y: 10.4 };
552 let p2 = Point { x: "Hello", y: 'c'};
554 let p3 = p1.mixup(p2);
556 println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
560 Listing 10-10: Methods that use different generic types than their struct’s
563 In `main`, we’ve defined a `Point` that has an `i32` for `x` (with value `5`)
564 and an `f64` for `y` (with value `10.4`). `p2` is a `Point` that has a string
565 slice for `x` (with value `"Hello"`) and a `char` for `y` (with value `c`).
566 Calling `mixup` on `p1` with the argument `p2` gives us `p3`, which will have
567 an `i32` for `x`, since `x` came from `p1`. `p3` will have a `char` for `y`,
568 since `y` came from `p2`. The `println!` will print `p3.x = 5, p3.y = c`.
570 Note that the generic parameters `T` and `U` are declared after `impl`, since
571 they go with the struct definition. The generic parameters `V` and `W` are
572 declared after `fn mixup`, since they are only relevant to the method.
574 ### Performance of Code Using Generics
576 You may have been reading this section and wondering if there’s a run-time cost
577 to using generic type parameters. Good news: the way that Rust has implemented
578 generics means that your code will not run any slower than if you had specified
579 concrete types instead of generic type parameters!
581 Rust accomplishes this by performing *monomorphization* of code using generics
582 at compile time. Monomorphization is the process of turning generic code into
583 specific code with the concrete types that are actually used filled in.
585 What the compiler does is the opposite of the steps that we performed to create
586 the generic function in Listing 10-5. The compiler looks at all the places that
587 generic code is called and generates code for the concrete types that the
588 generic code is called with.
590 Let’s work through an example that uses the standard library’s `Option` enum:
593 let integer = Some(5);
594 let float = Some(5.0);
597 When Rust compiles this code, it will perform monomorphization. The compiler
598 will read the values that have been passed to `Option` and see that we have two
599 kinds of `Option<T>`: one is `i32`, and one is `f64`. As such, it will expand
600 the generic definition of `Option<T>` into `Option_i32` and `Option_f64`,
601 thereby replacing the generic definition with the specific ones.
603 The monomorphized version of our code that the compiler generates looks like
604 this, with the uses of the generic `Option` replaced with the specific
605 definitions created by the compiler:
607 Filename: src/main.rs
621 let integer = Option_i32::Some(5);
622 let float = Option_f64::Some(5.0);
626 We can write the non-duplicated code using generics, and Rust will compile that
627 into code that specifies the type in each instance. That means we pay no
628 runtime cost for using generics; when the code runs, it performs just like it
629 would if we had duplicated each particular definition by hand. The process of
630 monomorphization is what makes Rust’s generics extremely efficient at runtime.
632 ## Traits: Defining Shared Behavior
634 Traits allow us to use another kind of abstraction: they let us abstract over
635 behavior that types can have in common. A *trait* tells the Rust compiler about
636 functionality a particular type has and might share with other types. In
637 situations where we use generic type parameters, we can use *trait bounds* to
638 specify, at compile time, that the generic type may be any type that implements
639 a trait and therefore has the behavior we want to use in that situation.
641 > Note: *Traits* are similar to a feature often called ‘interfaces’ in other
642 > languages, though with some differences.
646 The behavior of a type consists of the methods we can call on that type.
647 Different types share the same behavior if we can call the same methods on all
648 of those types. Trait definitions are a way to group method signatures together
649 in order to define a set of behaviors necessary to accomplish some purpose.
651 For example, say we have multiple structs that hold various kinds and amounts
652 of text: a `NewsArticle` struct that holds a news story filed in a particular
653 place in the world, and a `Tweet` that can have at most 140 characters in its
654 content along with metadata like whether it was a retweet or a reply to another
657 We want to make a media aggregator library that can display summaries of data
658 that might be stored in a `NewsArticle` or `Tweet` instance. The behavior we
659 need each struct to have is that it’s able to be summarized, and that we can
660 ask for that summary by calling a `summary` method on an instance. Listing
661 10-11 shows the definition of a `Summarizable` trait that expresses this
667 pub trait Summarizable {
668 fn summary(&self) -> String;
672 Listing 10-11: Definition of a `Summarizable` trait that consists of the
673 behavior provided by a `summary` method
675 We declare a trait with the `trait` keyword, then the trait’s name, in this
676 case `Summarizable`. Inside curly braces we declare the method signatures that
677 describe the behaviors that types that implement this trait will need to have,
678 in this case `fn summary(&self) -> String`. After the method signature, instead
679 of providing an implementation within curly braces, we put a semicolon. Each
680 type that implements this trait must then provide its own custom behavior for
681 the body of the method, but the compiler will enforce that any type that has
682 the `Summarizable` trait will have the method `summary` defined for it with
683 this signature exactly.
685 A trait can have multiple methods in its body, with the method signatures
686 listed one per line and each line ending in a semicolon.
688 ### Implementing a Trait on a Type
690 Now that we’ve defined the `Summarizable` trait, we can implement it on the
691 types in our media aggregator that we want to have this behavior. Listing 10-12
692 shows an implementation of the `Summarizable` trait on the `NewsArticle` struct
693 that uses the headline, the author, and the location to create the return value
694 of `summary`. For the `Tweet` struct, we’ve chosen to define `summary` as the
695 username followed by the whole text of the tweet, assuming that tweet content
696 is already limited to 140 characters.
701 pub struct NewsArticle {
702 pub headline: String,
703 pub location: String,
708 impl Summarizable for NewsArticle {
709 fn summary(&self) -> String {
710 format!("{}, by {} ({})", self.headline, self.author, self.location)
715 pub username: String,
721 impl Summarizable for Tweet {
722 fn summary(&self) -> String {
723 format!("{}: {}", self.username, self.content)
728 Listing 10-12: Implementing the `Summarizable` trait on the `NewsArticle` and
731 Implementing a trait on a type is similar to implementing methods that aren’t
732 related to a trait. The difference is after `impl`, we put the trait name that
733 we want to implement, then say `for` and the name of the type that we want to
734 implement the trait for. Within the `impl` block, we put the method signatures
735 that the trait definition has defined, but instead of putting a semicolon after
736 each signature, we put curly braces and fill in the method body with the
737 specific behavior that we want the methods of the trait to have for the
740 Once we’ve implemented the trait, we can call the methods on instances of
741 `NewsArticle` and `Tweet` in the same manner that we call methods that aren’t
746 username: String::from("horse_ebooks"),
747 content: String::from("of course, as you probably already know, people"),
752 println!("1 new tweet: {}", tweet.summary());
755 This will print `1 new tweet: horse_ebooks: of course, as you probably already
758 Note that because we’ve defined the `Summarizable` trait and the `NewsArticle`
759 and `Tweet` types all in the same `lib.rs` in Listing 10-12, they’re all in the
760 same scope. If this `lib.rs` is for a crate we’ve called `aggregator`, and
761 someone else wants to use our crate’s functionality plus implement the
762 `Summarizable` trait on their `WeatherForecast` struct, their code would need
763 to import the `Summarizable` trait into their scope first before they could
764 implement it, like in Listing 10-13:
769 extern crate aggregator;
771 use aggregator::Summarizable;
773 struct WeatherForecast {
776 chance_of_precipitation: f64,
779 impl Summarizable for WeatherForecast {
780 fn summary(&self) -> String {
781 format!("The high will be {}, and the low will be {}. The chance of
782 precipitation is {}%.", self.high_temp, self.low_temp,
783 self.chance_of_precipitation)
788 Listing 10-13: Bringing the `Summarizable` trait from our `aggregator` crate
789 into scope in another crate
791 This code also assumes `Summarizable` is a public trait, which it is because we
792 put the `pub` keyword before `trait` in Listing 10-11.
794 One restriction to note with trait implementations: we may implement a trait on
795 a type as long as either the trait or the type are local to our crate. In other
796 words, we aren’t allowed to implement external traits on external types. We
797 can’t implement the `Display` trait on `Vec`, for example, since both `Display`
798 and `Vec` are defined in the standard library. We are allowed to implement
799 standard library traits like `Display` on a custom type like `Tweet` as part of
800 our `aggregator` crate functionality. We could also implement `Summarizable` on
801 `Vec` in our `aggregator` crate, since we’ve defined `Summarizable` there. This
802 restriction is part of what’s called the *orphan rule*, which you can look up
803 if you’re interested in type theory. Briefly, it’s called the orphan rule
804 because the parent type is not present. Without this rule, two crates could
805 implement the same trait for the same type, and the two implementations would
806 conflict: Rust wouldn’t know which implementation to use. Because Rust enforces
807 the orphan rule, other people’s code can’t break your code and vice versa.
809 ### Default Implementations
811 Sometimes it’s useful to have default behavior for some or all of the methods
812 in a trait, instead of making every implementation on every type define custom
813 behavior. When we implement the trait on a particular type, we can choose to
814 keep or override each method’s default behavior.
816 Listing 10-14 shows how we could have chosen to specify a default string for
817 the `summary` method of the `Summarize` trait instead of only choosing to only
818 define the method signature like we did in Listing 10-11:
823 pub trait Summarizable {
824 fn summary(&self) -> String {
825 String::from("(Read more...)")
830 Listing 10-14: Definition of a `Summarizable` trait with a default
831 implementation of the `summary` method
833 If we wanted to use this default implementation to summarize instances of
834 `NewsArticle` instead of defining a custom implementation like we did in
835 Listing 10-12, we would specify an empty `impl` block:
838 impl Summarizable for NewsArticle {}
841 Even though we’re no longer choosing to define the `summary` method on
842 `NewsArticle` directly, since the `summary` method has a default implementation
843 and we specified that `NewsArticle` implements the `Summarizable` trait, we can
844 still call the `summary` method on an instance of `NewsArticle`:
847 let article = NewsArticle {
848 headline: String::from("Penguins win the Stanley Cup Championship!"),
849 location: String::from("Pittsburgh, PA, USA"),
850 author: String::from("Iceburgh"),
851 content: String::from("The Pittsburgh Penguins once again are the best
852 hockey team in the NHL."),
855 println!("New article available! {}", article.summary());
858 This code prints `New article available! (Read more...)`.
860 Changing the `Summarizable` trait to have a default implementation for
861 `summary` does not require us to change anything about the implementations of
862 `Summarizable` on `Tweet` in Listing 10-12 or `WeatherForecast` in Listing
863 10-13: the syntax for overriding a default implementation is exactly the same
864 as the syntax for implementing a trait method that doesn’t have a default
867 Default implementations are allowed to call the other methods in the same
868 trait, even if those other methods don’t have a default implementation. In this
869 way, a trait can provide a lot of useful functionality and only require
870 implementers to specify a small part of it. We could choose to have the
871 `Summarizable` trait also have an `author_summary` method whose implementation
872 is required, then a `summary` method that has a default implementation that
873 calls the `author_summary` method:
876 pub trait Summarizable {
877 fn author_summary(&self) -> String;
879 fn summary(&self) -> String {
880 format!("(Read more from {}...)", self.author_summary())
885 In order to use this version of `Summarizable`, we’re only required to define
886 `author_summary` when we implement the trait on a type:
889 impl Summarizable for Tweet {
890 fn author_summary(&self) -> String {
891 format!("@{}", self.username)
896 Once we define `author_summary`, we can call `summary` on instances of the
897 `Tweet` struct, and the default implementation of `summary` will call the
898 definition of `author_summary` that we’ve provided.
902 username: String::from("horse_ebooks"),
903 content: String::from("of course, as you probably already know, people"),
908 println!("1 new tweet: {}", tweet.summary());
911 This will print `1 new tweet: (Read more from @horse_ebooks...)`.
913 Note that it is not possible to call the default implementation from an
914 overridden implementation.
918 Now that we’ve defined traits and implemented those traits on types, we can use
919 traits with generic type parameters. We can constrain generic types so that
920 rather than being any type, the compiler will ensure that the type will be
921 limited to those types that implement a particular trait and thus have the
922 behavior that we need the types to have. This is called specifying *trait
923 bounds* on a generic type.
925 For example, in Listing 10-12, we implemented the `Summarizable` trait on the
926 types `NewsArticle` and `Tweet`. We can define a function `notify` that calls
927 the `summary` method on its parameter `item`, which is of the generic type `T`.
928 To be able to call `summary` on `item` without getting an error, we can use
929 trait bounds on `T` to specify that `item` must be of a type that implements
930 the `Summarizable` trait:
933 pub fn notify<T: Summarizable>(item: T) {
934 println!("Breaking news! {}", item.summary());
938 Trait bounds go with the declaration of the generic type parameter, after a
939 colon and within the angle brackets. Because of the trait bound on `T`, we can
940 call `notify` and pass in any instance of `NewsArticle` or `Tweet`. The
941 external code from Listing 10-13 that’s using our `aggregator` crate can call
942 our `notify` function and pass in an instance of `WeatherForecast`, since
943 `Summarizable` is implemented for `WeatherForecast` as well. Code that calls
944 `notify` with any other type, like a `String` or an `i32`, won’t compile, since
945 those types do not implement `Summarizable`.
947 We can specify multiple trait bounds on a generic type by using `+`. If we
948 needed to be able to use display formatting on the type `T` in a function as
949 well as the `summary` method, we can use the trait bounds `T: Summarizable +
950 Display`. This means `T` can be any type that implements both `Summarizable`
953 For functions that have multiple generic type parameters, each generic has its
954 own trait bounds. Specifying lots of trait bound information in the angle
955 brackets between a function’s name and its parameter list can get hard to read,
956 so there’s an alternate syntax for specifying trait bounds that lets us move
957 them to a `where` clause after the function signature. So instead of:
960 fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {
963 We can write this instead with a `where` clause:
966 fn some_function<T, U>(t: T, u: U) -> i32
967 where T: Display + Clone,
972 This is less cluttered and makes this function’s signature look more similar to
973 a function without lots of trait bounds, in that the function name, parameter
974 list, and return type are close together.
976 ### Fixing the `largest` Function with Trait Bounds
978 So any time you want to use behavior defined by a trait on a generic, you need
979 to specify that trait in the generic type parameter’s type bounds. We can now
980 fix the definition of the `largest` function that uses a generic type parameter
981 from Listing 10-5! When we set that code aside, we were getting this error:
984 error[E0369]: binary operation `>` cannot be applied to type `T`
986 5 | if item > largest {
989 note: an implementation of `std::cmp::PartialOrd` might be missing for `T`
992 In the body of `largest` we wanted to be able to compare two values of type `T`
993 using the greater-than operator. That operator is defined as a default method
994 on the standard library trait `std::cmp::PartialOrd`. So in order to be able to
995 use the greater-than operator, we need to specify `PartialOrd` in the trait
996 bounds for `T` so that the `largest` function will work on slices of any type
997 that can be compared. We don’t need to bring `PartialOrd` into scope because
1001 fn largest<T: PartialOrd>(list: &[T]) -> T {
1004 If we try to compile this, we’ll get different errors:
1007 error[E0508]: cannot move out of type `[T]`, a non-copy array
1008 --> src/main.rs:4:23
1010 4 | let mut largest = list[0];
1011 | ----------- ^^^^^^^ cannot move out of here
1013 | hint: to prevent move, use `ref largest` or `ref mut largest`
1015 error[E0507]: cannot move out of borrowed content
1018 6 | for &item in list.iter() {
1021 | |hint: to prevent move, use `ref item` or `ref mut item`
1022 | cannot move out of borrowed content
1025 The key to this error is `cannot move out of type [T], a non-copy array`.
1026 With our non-generic versions of the `largest` function, we were only trying to
1027 find the largest `i32` or `char`. As we discussed in Chapter 4, types like
1028 `i32` and `char` that have a known size can be stored on the stack, so they
1029 implement the `Copy` trait. When we changed the `largest` function to be
1030 generic, it’s now possible that the `list` parameter could have types in it
1031 that don’t implement the `Copy` trait, which means we wouldn’t be able to move
1032 the value out of `list[0]` and into the `largest` variable.
1034 If we only want to be able to call this code with types that are `Copy`, we can
1035 add `Copy` to the trait bounds of `T`! Listing 10-15 shows the complete code of
1036 a generic `largest` function that will compile as long as the types of the
1037 values in the slice that we pass into `largest` implement both the `PartialOrd`
1038 and `Copy` traits, like `i32` and `char`:
1040 Filename: src/main.rs
1043 use std::cmp::PartialOrd;
1045 fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
1046 let mut largest = list[0];
1048 for &item in list.iter() {
1058 let numbers = vec![34, 50, 25, 100, 65];
1060 let result = largest(&numbers);
1061 println!("The largest number is {}", result);
1063 let chars = vec!['y', 'm', 'a', 'q'];
1065 let result = largest(&chars);
1066 println!("The largest char is {}", result);
1070 Listing 10-15: A working definition of the `largest` function that works on any
1071 generic type that implements the `PartialOrd` and `Copy` traits
1073 If we don’t want to restrict our `largest` function to only types that
1074 implement the `Copy` trait, we could specify that `T` has the trait bound
1075 `Clone` instead of `Copy` and clone each value in the slice when we want the
1076 `largest` function to have ownership. Using the `clone` function means we’re
1077 potentially making more heap allocations, though, and heap allocations can be
1078 slow if we’re working with large amounts of data. Another way we could
1079 implement `largest` is for the function to return a reference to a `T` value in
1080 the slice. If we change the return type to be `&T` instead of `T` and change
1081 the body of the function to return a reference, we wouldn’t need either the
1082 `Clone` or `Copy` trait bounds and we wouldn’t be doing any heap allocations.
1083 Try implementing these alternate solutions on your own!
1085 Traits and trait bounds let us write code that uses generic type parameters in
1086 order to reduce duplication, but still specify to the compiler exactly what
1087 behavior our code needs the generic type to have. Because we’ve given the trait
1088 bound information to the compiler, it can check that all the concrete types
1089 used with our code provide the right behavior. In dynamically typed languages,
1090 if we tried to call a method on a type that the type didn’t implement, we’d get
1091 an error at runtime. Rust moves these errors to compile time so that we’re
1092 forced to fix the problems before our code is even able to run. Additionally,
1093 we don’t have to write code that checks for behavior at runtime since we’ve
1094 already checked at compile time, which improves performance compared to other
1095 languages without having to give up the flexibility of generics.
1097 There’s another kind of generics that we’ve been using without even realizing
1098 it called *lifetimes*. Rather than helping us ensure that a type has the
1099 behavior we need it to have, lifetimes help us ensure that references are valid
1100 as long as we need them to be. Let’s learn how lifetimes do that.
1102 ## Validating References with Lifetimes
1104 When we talked about references in Chapter 4, we left out an important detail:
1105 every reference in Rust has a *lifetime*, which is the scope for which that
1106 reference is valid. Most of the time lifetimes are implicit and inferred, just
1107 like most of the time types are inferred. Similarly to when we have to annotate
1108 types because multiple types are possible, there are cases where the lifetimes
1109 of references could be related in a few different ways, so Rust needs us to
1110 annotate the relationships using generic lifetime parameters so that it can
1111 make sure the actual references used at runtime will definitely be valid.
1113 Yes, it’s a bit unusual, and will be different to tools you’ve used in other
1114 programming languages. Lifetimes are, in some ways, Rust’s most distinctive
1117 Lifetimes are a big topic that can’t be covered in entirety in this chapter, so
1118 we’ll cover common ways you might encounter lifetime syntax in this chapter to
1119 get you familiar with the concepts. Chapter 19 will contain more advanced
1120 information about everything lifetimes can do.
1122 ### Lifetimes Prevent Dangling References
1124 The main aim of lifetimes is to prevent dangling references, which will cause a
1125 program to reference data other than the data we’re intending to reference.
1126 Consider the program in Listing 10-16, with an outer scope and an inner scope.
1127 The outer scope declares a variable named `r` with no initial value, and the
1128 inner scope declares a variable named `x` with the initial value of 5. Inside
1129 the inner scope, we attempt to set the value of `r` as a reference to `x`. Then
1130 the inner scope ends, and we attempt to print out the value in `r`:
1141 println!("r: {}", r);
1145 Listing 10-16: An attempt to use a reference whose value has gone out of scope
1147 > #### Uninitialized Variables Cannot Be Used
1149 > The next few examples declare variables without giving them an initial value,
1150 > so that the variable name exists in the outer scope. This might appear to be
1151 > in conflict with Rust not having null. However, if we try to use a variable
1152 > before giving it a value, we’ll get a compile-time error. Try it out!
1154 When we compile this code, we’ll get an error:
1157 error: `x` does not live long enough
1160 | - borrow occurs here
1162 | ^ `x` dropped here while still borrowed
1165 | - borrowed value needs to live until here
1168 The variable `x` doesn’t “live long enough.” Why not? Well, `x` is going to go
1169 out of scope when we hit the closing curly brace on line 7, ending the inner
1170 scope. But `r` is valid for the outer scope; its scope is larger and we say
1171 that it “lives longer.” If Rust allowed this code to work, `r` would be
1172 referencing memory that was deallocated when `x` went out of scope, and
1173 anything we tried to do with `r` wouldn’t work correctly. So how does Rust
1174 determine that this code should not be allowed?
1176 #### The Borrow Checker
1178 The part of the compiler called the *borrow checker* compares scopes to
1179 determine that all borrows are valid. Listing 10-17 shows the same example from
1180 Listing 10-16 with annotations showing the lifetimes of the variables:
1184 let r; // -------+-- 'a
1187 let x = 5; // -+-----+-- 'b
1191 println!("r: {}", r); // |
1197 Listing 10-17: Annotations of the lifetimes of `x` and `r`, named `'a` and `'b`
1200 <!-- Just checking I'm reading this right: the inside block is the b lifetime,
1201 correct? I want to leave a note for production, make sure we can make that
1203 <!-- Yes, the inside block for the `'b` lifetime starts with the `let x = 5;`
1204 line and ends with the first closing curly brace on the 7th line. Do you think
1205 the text art comments work or should we make an SVG diagram that has nicer
1206 looking arrows and labels? /Carol -->
1208 We’ve annotated the lifetime of `r` with `'a` and the lifetime of `x` with
1209 `'b`. As you can see, the inner `'b` block is much smaller than the outer `'a`
1210 lifetime block. At compile time, Rust compares the size of the two lifetimes
1211 and sees that `r` has a lifetime of `'a`, but that it refers to an object with
1212 a lifetime of `'b`. The program is rejected because the lifetime `'b` is
1213 shorter than the lifetime of `'a`: the subject of the reference does not live
1214 as long as the reference.
1216 Let’s look at an example in Listing 10-18 that doesn’t try to make a dangling
1217 reference and compiles without any errors:
1221 let x = 5; // -----+-- 'b
1223 let r = &x; // --+--+-- 'a
1225 println!("r: {}", r); // | |
1230 Listing 10-18: A valid reference because the data has a longer lifetime than
1233 Here, `x` has the lifetime `'b`, which in this case is larger than `'a`. This
1234 means `r` can reference `x`: Rust knows that the reference in `r` will always
1235 be valid while `x` is valid.
1237 Now that we’ve shown where the lifetimes of references are in a concrete
1238 example and discussed how Rust analyzes lifetimes to ensure references will
1239 always be valid, let’s talk about generic lifetimes of parameters and return
1240 values in the context of functions.
1242 ### Generic Lifetimes in Functions
1244 Let’s write a function that will return the longest of two string slices. We
1245 want to be able to call this function by passing it two string slices, and we
1246 want to get back a string slice. The code in Listing 10-19 should print `The
1247 longest string is abcd` once we’ve implemented the `longest` function:
1249 Filename: src/main.rs
1253 let string1 = String::from("abcd");
1254 let string2 = "xyz";
1256 let result = longest(string1.as_str(), string2);
1257 println!("The longest string is {}", result);
1261 Listing 10-19: A `main` function that calls the `longest` function to find the
1262 longest of two string slices
1264 Note that we want the function to take string slices (which are references, as
1265 we talked about in Chapter 4) since we don’t want the `longest` function to
1266 take ownership of its arguments. We want the function to be able to accept
1267 slices of a `String` (which is the type of the variable `string1`) as well as
1268 string literals (which is what variable `string2` contains).
1270 <!-- why is `a` a slice and `b` a literal? You mean "a" from the string "abcd"? -->
1271 <!-- I've changed the variable names to remove ambiguity between the variable
1272 name `a` and the "a" from the string "abcd". `string1` is not a slice, it's a
1273 `String`, but we're going to pass a slice that refers to that `String` to the
1274 `longest` function (`string1.as_str()` creates a slice that references the
1275 `String` stored in `string1`). We chose to have `string2` be a literal since
1276 the reader might have code with both `String`s and string literals, and the way
1277 most readers first get into problems with lifetimes is involving string slices,
1278 so we wanted to demonstrate the flexibility of taking string slices as
1279 arguments but the issues you might run into because string slices are
1281 All of the `String`/string slice/string literal concepts here are covered
1282 thoroughly in Chapter 4, which is why we put two back references here (above
1283 and below). If these topics are confusing you in this context, I'd be
1284 interested to know if rereading Chapter 4 clears up that confusion.
1287 Refer back to the “String Slices as Arguments” section of Chapter 4 for more
1288 discussion about why these are the arguments we want.
1290 If we try to implement the `longest` function as shown in Listing 10-20, it
1293 Filename: src/main.rs
1296 fn longest(x: &str, y: &str) -> &str {
1297 if x.len() > y.len() {
1305 Listing 10-20: An implementation of the `longest` function that returns the
1306 longest of two string slices, but does not yet compile
1308 Instead we get the following error that talks about lifetimes:
1311 error[E0106]: missing lifetime specifier
1313 1 | fn longest(x: &str, y: &str) -> &str {
1314 | ^ expected lifetime parameter
1316 = help: this function's return type contains a borrowed value, but the
1317 signature does not say whether it is borrowed from `x` or `y`
1320 The help text is telling us that the return type needs a generic lifetime
1321 parameter on it because Rust can’t tell if the reference being returned refers
1322 to `x` or `y`. Actually, we don’t know either, since the `if` block in the body
1323 of this function returns a reference to `x` and the `else` block returns a
1326 As we’re defining this function, we don’t know the concrete values that will be
1327 passed into this function, so we don’t know whether the `if` case or the `else`
1328 case will execute. We also don’t know the concrete lifetimes of the references
1329 that will be passed in, so we can’t look at the scopes like we did in Listings
1330 10-17 and 10-18 in order to determine that the reference we return will always
1331 be valid. The borrow checker can’t determine this either, because it doesn’t
1332 know how the lifetimes of `x` and `y` relate to the lifetime of the return
1333 value. We’re going to add generic lifetime parameters that will define the
1334 relationship between the references so that the borrow checker can perform its
1337 ### Lifetime Annotation Syntax
1339 Lifetime annotations don’t change how long any of the references involved live.
1340 In the same way that functions can accept any type when the signature specifies
1341 a generic type parameter, functions can accept references with any lifetime
1342 when the signature specifies a generic lifetime parameter. What lifetime
1343 annotations do is relate the lifetimes of multiple references to each other.
1345 Lifetime annotations have a slightly unusual syntax: the names of lifetime
1346 parameters must start with an apostrophe `'`. The names of lifetime parameters
1347 are usually all lowercase, and like generic types, their names are usually very
1348 short. `'a` is the name most people use as a default. Lifetime parameter
1349 annotations go after the `&` of a reference, and a space separates the lifetime
1350 annotation from the reference’s type.
1352 Here’s some examples: we’ve got a reference to an `i32` without a lifetime
1353 parameter, a reference to an `i32` that has a lifetime parameter named `'a`,
1354 and a mutable reference to an `i32` that also has the lifetime `'a`:
1358 &'a i32 // a reference with an explicit lifetime
1359 &'a mut i32 // a mutable reference with an explicit lifetime
1362 One lifetime annotation by itself doesn’t have much meaning: lifetime
1363 annotations tell Rust how the generic lifetime parameters of multiple
1364 references relate to each other. If we have a function with the parameter
1365 `first` that is a reference to an `i32` that has the lifetime `'a`, and the
1366 function has another parameter named `second` that is another reference to an
1367 `i32` that also has the lifetime `'a`, these two lifetime annotations that have
1368 the same name indicate that the references `first` and `second` must both live
1369 as long as the same generic lifetime.
1371 ### Lifetime Annotations in Function Signatures
1373 Let’s look at lifetime annotations in the context of the `longest` function
1374 we’re working on. Just like generic type parameters, generic lifetime
1375 parameters need to be declared within angle brackets between the function name
1376 and the parameter list. The constraint we want to tell Rust about for the
1377 references in the parameters and the return value is that they all must have
1378 the same lifetime, which we’ll name `'a` and add to each reference as shown in
1381 Filename: src/main.rs
1384 fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
1385 if x.len() > y.len() {
1393 Listing 10-21: The `longest` function definition that specifies all the
1394 references in the signature must have the same lifetime, `'a`
1396 This will compile and will produce the result we want when used with the `main`
1397 function in Listing 10-19.
1399 The function signature now says that for some lifetime `'a`, the function will
1400 get two parameters, both of which are string slices that live at least as long
1401 as the lifetime `'a`. The function will return a string slice that also will
1402 last at least as long as the lifetime `'a`. This is the contract we are telling
1403 Rust we want it to enforce.
1405 By specifying the lifetime parameters in this function signature, we are not
1406 changing the lifetimes of any values passed in or returned, but we are saying
1407 that any values that do not adhere to this contract should be rejected by the
1408 borrow checker. This function does not know (or need to know) exactly how long
1409 `x` and `y` will live, but only needs to knows that there is some scope that
1410 can be substituted for `'a` that will satisfy this signature.
1412 When annotating lifetimes in functions, the annotations go on the function
1413 signature, and not in any of the code in the function body. This is because
1414 Rust is able analyze the code within the function without any help, but when a
1415 function has references to or from code outside that function, the lifetimes of
1416 the arguments or return values will potentially be different each time the
1417 function is called. This would be incredibly costly and often impossible for
1418 Rust to figure out. In this case, we need to annotate the lifetimes ourselves.
1420 When concrete references are passed to `longest`, the concrete lifetime that
1421 gets substituted for `'a` is the part of the scope of `x` that overlaps with
1422 the scope of `y`. Since scopes always nest, another way to say this is that the
1423 generic lifetime `'a` will get the concrete lifetime equal to the smaller of
1424 the lifetimes of `x` and `y`. Because we’ve annotated the returned reference
1425 with the same lifetime parameter `'a`, the returned reference will therefore be
1426 guaranteed to be valid as long as the shorter of the lifetimes of `x` and `y`.
1428 Let’s see how this restricts the usage of the `longest` function by passing in
1429 references that have different concrete lifetimes. Listing 10-22 is a
1430 straightforward example that should match your intuition from any language:
1431 `string1` is valid until the end of the outer scope, `string2` is valid until
1432 the end of the inner scope, and `result` references something that is valid
1433 until the end of the outer scope. The borrow checker approves of this code; it
1434 will compile and print `The longest string is long string is long` when run:
1436 Filename: src/main.rs
1440 let string1 = String::from("long string is long");
1443 let string2 = String::from("xyz");
1444 let result = longest(string1.as_str(), string2.as_str());
1445 println!("The longest string is {}", result);
1450 Listing 10-22: Using the `longest` function with references to `String` values
1451 that have different concrete lifetimes
1453 Next, let’s try an example that will show that the lifetime of the reference in
1454 `result` must be the smaller lifetime of the two arguments. We’ll move the
1455 declaration of the `result` variable outside the inner scope, but leave the
1456 assignment of the value to the `result` variable inside the scope with
1457 `string2`. Next, we’ll move the `println!` that uses `result` outside of the
1458 inner scope, after it has ended. The code in Listing 10-23 will not compile:
1460 Filename: src/main.rs
1464 let string1 = String::from("long string is long");
1467 let string2 = String::from("xyz");
1468 result = longest(string1.as_str(), string2.as_str());
1470 println!("The longest string is {}", result);
1474 Listing 10-23: Attempting to use `result` after `string2` has gone out of scope
1477 If we try to compile this, we’ll get this error:
1480 error: `string2` does not live long enough
1482 6 | result = longest(string1.as_str(), string2.as_str());
1483 | ------- borrow occurs here
1485 | ^ `string2` dropped here while still borrowed
1486 8 | println!("The longest string is {}", result);
1488 | - borrowed value needs to live until here
1491 The error is saying that in order for `result` to be valid for the `println!`,
1492 `string2` would need to be valid until the end of the outer scope. Rust knows
1493 this because we annotated the lifetimes of the function parameters and return
1494 values with the same lifetime parameter, `'a`.
1496 We can look at this code as humans and see that `string1` is longer, and
1497 therefore `result` will contain a reference to `string1`. Because `string1` has
1498 not gone out of scope yet, a reference to `string1` will still be valid for the
1499 `println!`. However, what we’ve told Rust with the lifetime parameters is that
1500 the lifetime of the reference returned by the `longest` function is the same as
1501 the smaller of the lifetimes of the references passed in. Therefore, the borrow
1502 checker disallows the code in Listing 10-23 as possibly having an invalid
1505 Try designing some more experiments that vary the values and lifetimes of the
1506 references passed in to the `longest` function and how the returned reference
1507 is used. Make hypotheses about whether your experiments will pass the borrow
1508 checker or not before you compile, then check to see if you’re right!
1510 ### Thinking in Terms of Lifetimes
1512 The exact way to specify lifetime parameters depends on what your function is
1513 doing. For example, if we changed the implementation of the `longest` function
1514 to always return the first argument rather than the longest string slice, we
1515 wouldn’t need to specify a lifetime on the `y` parameter. This code compiles:
1517 Filename: src/main.rs
1520 fn longest<'a>(x: &'a str, y: &str) -> &'a str {
1525 In this example, we’ve specified a lifetime parameter `'a` for the parameter
1526 `x` and the return type, but not for the parameter `y`, since the lifetime of
1527 `y` does not have any relationship with the lifetime of `x` or the return value.
1529 When returning a reference from a function, the lifetime parameter for the
1530 return type needs to match the lifetime parameter of one of the arguments. If
1531 the reference returned does *not* refer to one of the arguments, the only other
1532 possibility is that it refers to a value created within this function, which
1533 would be a dangling reference since the value will go out of scope at the end
1534 of the function. Consider this attempted implementation of the `longest`
1535 function that won’t compile:
1537 Filename: src/main.rs
1540 fn longest<'a>(x: &str, y: &str) -> &'a str {
1541 let result = String::from("really long string");
1546 Even though we’ve specified a lifetime parameter `'a` for the return type, this
1547 implementation fails to compile because the return value lifetime is not
1548 related to the lifetime of the parameters at all. Here’s the error message we
1552 error: `result` does not live long enough
1555 | ^^^^^^ does not live long enough
1557 | - borrowed value only lives until here
1559 note: borrowed value must be valid for the lifetime 'a as defined on the block
1562 1 | fn longest<'a>(x: &str, y: &str) -> &'a str {
1566 The problem is that `result` will go out of scope and get cleaned up at the end
1567 of the `longest` function, and we’re trying to return a reference to `result`
1568 from the function. There’s no way we can specify lifetime parameters that would
1569 change the dangling reference, and Rust won’t let us create a dangling
1570 reference. In this case, the best fix would be to return an owned data type
1571 rather than a reference so that the calling function is then responsible for
1572 cleaning up the value.
1574 Ultimately, lifetime syntax is about connecting the lifetimes of various
1575 arguments and return values of functions. Once they’re connected, Rust has
1576 enough information to allow memory-safe operations and disallow operations that
1577 would create dangling pointers or otherwise violate memory safety.
1579 ### Lifetime Annotations in Struct Definitions
1581 Up until now, we’ve only defined structs to hold owned types. It is possible
1582 for structs to hold references, but we need to add a lifetime annotation on
1583 every reference in the struct’s definition. Listing 10-24 has a struct named
1584 `ImportantExcerpt` that holds a string slice:
1586 Filename: src/main.rs
1589 struct ImportantExcerpt<'a> {
1594 let novel = String::from("Call me Ishmael. Some years ago...");
1595 let first_sentence = novel.split('.')
1597 .expect("Could not find a '.'");
1598 let i = ImportantExcerpt { part: first_sentence };
1602 Listing 10-24: A struct that holds a reference, so its definition needs a
1605 This struct has one field, `part`, that holds a string slice, which is a
1606 reference. Just like with generic data types, we have to declare the name of
1607 the generic lifetime parameter inside angle brackets after the name of the
1608 struct so that we can use the lifetime parameter in the body of the struct
1611 The `main` function here creates an instance of the `ImportantExcerpt` struct
1612 that holds a reference to the first sentence of the `String` owned by the
1615 ### Lifetime Elision
1617 In this section, we’ve learned that every reference has a lifetime, and we need
1618 to specify lifetime parameters for functions or structs that use references.
1619 However, in Chapter 4 we had a function in the “String Slices” section, shown
1620 again in Listing 10-25, that compiled without lifetime annotations:
1622 Filename: src/lib.rs
1625 fn first_word(s: &str) -> &str {
1626 let bytes = s.as_bytes();
1628 for (i, &item) in bytes.iter().enumerate() {
1638 Listing 10-25: A function we defined in Chapter 4 that compiled without
1639 lifetime annotations, even though the parameter and return type are references
1641 The reason this function compiles without lifetime annotations is historical:
1642 in early versions of pre-1.0 Rust, this indeed wouldn’t have compiled. Every
1643 reference needed an explicit lifetime. At that time, the function signature
1644 would have been written like this:
1647 fn first_word<'a>(s: &'a str) -> &'a str {
1650 After writing a lot of Rust code, the Rust team found that Rust programmers
1651 were typing the same lifetime annotations over and over in particular
1652 situations. These situations were predictable and followed a few deterministic
1653 patterns. The Rust team then programmed these patterns into the Rust compiler’s
1654 code so that the borrow checker can infer the lifetimes in these situations
1655 without forcing the programmer to explicitly add the annotations.
1657 We mention this piece of Rust history because it’s entirely possible that more
1658 deterministic patterns will emerge and be added to the compiler. In the future,
1659 even fewer lifetime annotations might be required.
1661 The patterns programmed into Rust’s analysis of references are called the
1662 *lifetime elision rules*. These aren’t rules for programmers to follow; the
1663 rules are a set of particular cases that the compiler will consider, and if
1664 your code fits these cases, you don’t need to write the lifetimes explicitly.
1666 The elision rules don’t provide full inference: if Rust deterministically
1667 applies the rules but there’s still ambiguity as to what lifetimes the
1668 references have, it won’t guess what the lifetime of the remaining references
1669 should be. In this case, the compiler will give you an error that can be
1670 resolved by adding the lifetime annotations that correspond to your intentions
1671 for how the references relate to each other.
1673 First, some definitions: Lifetimes on function or method parameters are called
1674 *input lifetimes*, and lifetimes on return values are called *output lifetimes*.
1676 Now, on to the rules that the compiler uses to figure out what lifetimes
1677 references have when there aren’t explicit annotations. The first rule applies
1678 to input lifetimes, and the second two rules apply to output lifetimes. If the
1679 compiler gets to the end of the three rules and there are still references that
1680 it can’t figure out lifetimes for, the compiler will stop with an error.
1682 1. Each parameter that is a reference gets its own lifetime parameter. In other
1683 words, a function with one parameter gets one lifetime parameter: `fn
1684 foo<'a>(x: &'a i32)`, a function with two arguments gets two separate
1685 lifetime parameters: `fn foo<'a, 'b>(x: &'a i32, y: &'b i32)`, and so on.
1687 2. If there is exactly one input lifetime parameter, that lifetime is assigned
1688 to all output lifetime parameters: `fn foo<'a>(x: &'a i32) -> &'a i32`.
1690 3. If there are multiple input lifetime parameters, but one of them is `&self`
1691 or `&mut self` because this is a method, then the lifetime of `self` is
1692 assigned to all output lifetime parameters. This makes writing methods much
1695 Let’s pretend we’re the compiler and apply these rules to figure out what the
1696 lifetimes of the references in the signature of the `first_word` function in
1697 Listing 10-25 are. The signatures starts without any lifetimes associated with
1701 fn first_word(s: &str) -> &str {
1704 Then we (as the compiler) apply the first rule, which says each parameter gets
1705 its own lifetime. We’re going to call it `'a` as usual, so now the signature is:
1708 fn first_word<'a>(s: &'a str) -> &str {
1711 On to the second rule, which applies because there is exactly one input
1712 lifetime. The second rule says the lifetime of the one input parameter gets
1713 assigned to the output lifetime, so now the signature is:
1716 fn first_word<'a>(s: &'a str) -> &'a str {
1719 Now all the references in this function signature have lifetimes, and the
1720 compiler can continue its analysis without needing the programmer to annotate
1721 the lifetimes in this function signature.
1723 Let’s do another example, this time with the `longest` function that had no
1724 lifetime parameters when we started working with in Listing 10-20:
1727 fn longest(x: &str, y: &str) -> &str {
1730 Pretending we’re the compiler again, let’s apply the first rule: each parameter
1731 gets its own lifetime. This time we have two parameters, so we have two
1735 fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {
1738 Looking at the second rule, it doesn’t apply since there is more than one input
1739 lifetime. Looking at the third rule, this also does not apply because this is a
1740 function rather than a method, so none of the parameters are `self`. So we’re
1741 out of rules, but we haven’t figured out what the return type’s lifetime is.
1742 This is why we got an error trying to compile the code from Listing 10-20: the
1743 compiler worked through the lifetime elision rules it knows, but still can’t
1744 figure out all the lifetimes of the references in the signature.
1746 Because the third rule only really applies in method signatures, let’s look at
1747 lifetimes in that context now, and see why the third rule means we don’t have
1748 to annotate lifetimes in method signatures very often.
1750 ### Lifetime Annotations in Method Definitions
1752 <!-- Is this different to the reference lifetime annotations, or just a
1753 finalized explanation? -->
1754 <!-- This is about lifetimes on references in method signatures, which is where
1755 the 3rd lifetime elision rule kicks in. It can also be confusing where lifetime
1756 parameters need to be declared and used since the lifetime parameters could go
1757 with the struct's fields or with references passed into or returned from
1760 When we implement methods on a struct with lifetimes, the syntax is again the
1761 same as that of generic type parameters that we showed in Listing 10-10: the
1762 place that lifetime parameters are declared and used depends on whether the
1763 lifetime parameter is related to the struct fields or the method arguments and
1766 Lifetime names for struct fields always need to be declared after the `impl`
1767 keyword and then used after the struct’s name, since those lifetimes are part
1768 of the struct’s type.
1770 In method signatures inside the `impl` block, references might be tied to the
1771 lifetime of references in the struct’s fields, or they might be independent. In
1772 addition, the lifetime elision rules often make it so that lifetime annotations
1773 aren’t necessary in method signatures. Let’s look at some examples using the
1774 struct named `ImportantExcerpt` that we defined in Listing 10-24.
1776 First, here’s a method named `level`. The only parameter is a reference to
1777 `self`, and the return value is just an `i32`, not a reference to anything:
1780 impl<'a> ImportantExcerpt<'a> {
1781 fn level(&self) -> i32 {
1787 The lifetime parameter declaration after `impl` and use after the type name is
1788 required, but we’re not required to annotate the lifetime of the reference to
1789 `self` because of the first elision rule.
1791 Here’s an example where the third lifetime elision rule applies:
1794 impl<'a> ImportantExcerpt<'a> {
1795 fn announce_and_return_part(&self, announcement: &str) -> &str {
1796 println!("Attention please: {}", announcement);
1802 There are two input lifetimes, so Rust applies the first lifetime elision rule
1803 and gives both `&self` and `announcement` their own lifetimes. Then, because
1804 one of the parameters is `&self`, the return type gets the lifetime of `&self`,
1805 and all lifetimes have been accounted for.
1807 ### The Static Lifetime
1809 There is *one* special lifetime we need to discuss: `'static`. The `'static`
1810 lifetime is the entire duration of the program. All string literals have the
1811 `'static` lifetime, which we can choose to annotate as follows:
1814 let s: &'static str = "I have a static lifetime.";
1817 The text of this string is stored directly in the binary of your program and
1818 the binary of your program is always available. Therefore, the lifetime of all
1819 string literals is `'static`.
1821 <!-- How would you add a static lifetime (below)? -->
1822 <!-- Just like you'd specify any lifetime, see above where it shows `&'static str`. /Carol -->
1824 You may see suggestions to use the `'static` lifetime in error message help
1825 text, but before specifying `'static` as the lifetime for a reference, think
1826 about whether the reference you have is one that actually lives the entire
1827 lifetime of your program or not (or even if you want it to live that long, if
1828 it could). Most of the time, the problem in the code is an attempt to create a
1829 dangling reference or a mismatch of the available lifetimes, and the solution
1830 is fixing those problems, not specifying the `'static` lifetime.
1832 ### Generic Type Parameters, Trait Bounds, and Lifetimes Together
1834 Let’s briefly look at the syntax of specifying generic type parameters, trait
1835 bounds, and lifetimes all in one function!
1838 use std::fmt::Display;
1840 fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
1843 println!("Announcement! {}", ann);
1844 if x.len() > y.len() {
1852 This is the `longest` function from Listing 10-21 that returns the longest of
1853 two string slices, but with an extra argument named `ann`. The type of `ann` is
1854 the generic type `T`, which may be filled in by any type that implements the
1855 `Display` trait as specified by the `where` clause. This extra argument will be
1856 printed out before the function compares the lengths of the string slices,
1857 which is why the `Display` trait bound is necessary. Because lifetimes are a
1858 type of generic, the declarations of both the lifetime parameter `'a` and the
1859 generic type parameter `T` go in the same list within the angle brackets after
1864 We covered a lot in this chapter! Now that you know about generic type
1865 parameters, traits and trait bounds, and generic lifetime parameters, you’re
1866 ready to write code that isn’t duplicated but can be used in many different
1867 situations. Generic type parameters mean the code can be applied to different
1868 types. Traits and trait bounds ensure that even though the types are generic,
1869 those types will have the behavior the code needs. Relationships between the
1870 lifetimes of references specified by lifetime annotations ensure that this
1871 flexible code won’t have any dangling references. And all of this happens at
1872 compile time so that run-time performance isn’t affected!
1874 Believe it or not, there’s even more to learn in these areas: Chapter 17 will
1875 discuss trait objects, which are another way to use traits. Chapter 19 will be
1876 covering more complex scenarios involving lifetime annotations. Chapter 20 will
1877 get to some advanced type system features. Up next, though, let’s talk about
1878 how to write tests in Rust so that we can make sure our code using all these
1879 features is working the way we want it to!