# Chapter 10 - Generic Types, Traits and Lifetimes
Generics are abstract stand-ins for concrete types or other properties.
## Generic Structs
``` rust
struct Point<T> {
x: T,
y: T,
}
fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
}
```
## Enum Structs
``` rust
enum Option<T> {
Some(T),
None,
}
```
## Generics in method definitions
``` rust
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
fn main() {
let p = Point { x: 5, y: 10 };
println!("p.x = {}", p.x());
}
```
### Traits: Defining shared behaviour
A trait tells the Rust compiler about functionality a particular type
has and can share with other types.
``` rust
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
pub trait Summary {
fn summarize(&self) -> String;
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
```
## Default implementations
``` rust
pub trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
```
To use a default implementation:
``` rust
impl Summary for Tweet {}
```
## Traits as Parameters
``` rust
pub fn notify(item: impl Summary) {
println!("Breaking news! {}", item.summarize());
}
```
## Trait Bound syntax
The `impl Trait` syntax in the above example works for straightforward
cases. It is actually a syntax sugar for a longer form which is called
a trait bound:
``` rust
pub fn notify<T: Summary>(item: T) {
println!("Breaking news! {}", item.summarize());
}
```
## Specifying Multiple Trait Bounds with the + Syntax
``` rust
pub fn notify(item: impl Summary + Display) {
```
Or in the trait bound syntax form:
``` rust
pub fn notify<T: Summary + Display>(item: T) {
```
## Clearer Trait Bounds with where Clauses
``` rust
fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {
```
can be written as:
``` rust
fn some_function<T, U>(t: T, u: U) -> i32
where T: Display + Clone,
U: Clone + Debug
{
```
## Returning Types that Implement Traits
``` rust
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}
```
### Validating references with Lifetimes
Every reference in Rust has a lifetime, which is the scope for which
that reference is valid.
## The Borrow Checker
The Rust compiler has a borrow checker that compares scopes to
determine whether all borrows are valid.
``` rust
{
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
} // ---------+
```
Here, we’ve annotated the lifetime of r with 'a and the lifetime of x
with 'b. As you can see, the inner 'b block is much smaller than the
outer 'a lifetime block. At compile time, Rust compares the size of
the two lifetimes and sees that r has a lifetime of 'a but that it
refers to memory with a lifetime of 'b. The program is rejected
because 'b is shorter than 'a: the subject of the reference doesn’t
live as long as the reference.
## Generic Lifetimes in Functions
This code will result in compile error:
``` rust
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
```
The error:
``` shellsession
error[E0106]: missing lifetime specifier
--> src/main.rs:1:33
|
1 | fn longest(x: &str, y: &str) -> &str {
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the
signature does not say whether it is borrowed from `x` or `y`
```
Rust can't tell whether the reference being returned refers to `x` or
`y`. To fix this error, we need to add generic lifetime parameters.
## Lifetime Annotation Syntax
* Lifetime annotations don’t change how long any of the references live.
* Lifetime annotations describe the relationships of the lifetimes of
multiple references to each other without affecting the lifetimes.
Lifetime annotations have a slightly unusual syntax: the names of
lifetime parameters must start with an apostrophe (') and are usually
all lowercase and very short, like generic types. Most people use the
name 'a. We place lifetime parameter annotations after the & of a
reference, using a space to separate the annotation from the
reference’s type.
``` rust
&i32 // a reference
&'a i32 // a reference with an explicit lifetime
&'a mut i32 // a mutable reference with an explicit lifetime
```
## Lifetime Annotations in Function Signatures
As with generic type parameters, we need to declare generic lifetime
parameters inside angle brackets between the function name and the
parameter list.
``` rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
```
## Lifetime Annotations in Struct Definitions
So far, we’ve only defined structs to hold owned types. It’s possible
for structs to hold references, but in that case we would need to add
a lifetime annotation on every reference in the struct’s definition.
``` rust
struct ImportantExcerpt<'a> {
part: &'a str,
}
```
## Lifetime Elision
You’ve learned that every reference has a lifetime and that you need
to specify lifetime parameters for functions or structs that use
references. But there are some code which seem to compile without
lifetime parameters:
``` rust
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
```
While the above code compiles with the recent version of Rust, it
would have not compiled in older versions of Rust.
After writing a lot of Rust code, the Rust team found that Rust
programmers were entering the same lifetime annotations over and over
in particular situations. These situations were predictable and
followed a few deterministic patterns. The developers programmed these
patterns into the compiler’s code so the borrow checker could infer
the lifetimes in these situations and wouldn’t need explicit
annotations.
The patterns programmed into Rust’s analysis of references are called
the lifetime elision rules.
Lifetimes on function or method parameters are called `input lifetimes`,
and lifetimes on return values are called `output lifetimes`.
The compiler uses three rules to figure out what lifetimes references
have when there aren’t explicit annotations. The first rule applies to
input lifetimes, and the second and third rules apply to output
lifetimes. These rules apply to fn definitions as well as impl
blocks:
* The first rule is that each parameter that is a reference gets its
own lifetime parameter. In other words, a function with one
parameter gets one lifetime parameter: `fn foo<'a>(x: &'a i32)`; a
function with two parameters gets two separate lifetime parameters:
`fn foo<'a, 'b>(x: &'a i32, y: &'b i32)`; and so on.
* The second rule is if there is exactly one input lifetime parameter,
that lifetime is assigned to all output lifetime parameters: `fn
foo<'a>(x: &'a i32) -> &'a i32`.
* The third rule is if there are multiple input lifetime parameters,
but one of them is `&self` or `&mut self` because this is a method,
the lifetime of `self` is assigned to all output lifetime
parameters. This third rule makes methods much nicer to read and
write because fewer symbols are necessary.
## Lifetime Annotations in Method Definitions
When we implement methods on a struct with lifetimes, we use the same
syntax as that of generic type parameters:
``` rust
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
}
```
The lifetime parameter declaration after `impl` and its use after the
type name are required, but we’re not required to annotate the
lifetime of the reference to `self` because of the first elision rule.
Example where the third lifetime elision rule applies:
``` rust
impl<'a> ImportantExcerpt<'a> {
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention please: {}", announcement);
self.part
}
}
```
There are two input lifetimes, so Rust applies the first lifetime
elision rule and gives both `&self` and announcement their own
lifetimes. Then, because one of the parameters is `&self`, the return
type gets the lifetime of `&self`, and all lifetimes have been
accounted for.
## The Static Lifetime
One special lifetime we need to discuss is `'static`, which means that
this reference can live for the entire duration of the program. All
string literals have the `'static` lifetime, which we can annotate as
follows:
``` rust
let s: &'static str = "I have a static lifetime.";
```
The text of this string is stored directly in the program’s binary,
which is always available. Therefore, the lifetime of all string
literals is `'static.`