C13: Generic Types, Traits, and Lifetimes Flashcards
generics
abstract stand-ins for concrete types or other properties
We can express the behavior of generics or how they relate to other generics without knowing what will be in their place when compiling and running the code.
lifetimes
Finally, we’ll discuss lifetimes: a variety of generics that give the compiler information about how references relate to each other. Lifetimes allow us to give the compiler enough information about borrowed values so that it can ensure references will be valid in more situations than it could without our help.
Lifetimes are another kind of generic that we’ve already been using. Rather than ensuring that a type has the behavior we want, lifetimes ensure that references are valid as long as we need them to be.
Generics example
struct Point<T> {
x: T,
y: T,
}</T>
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}</T></T>
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}</f32>
impl<X1, Y1> Point<X1, Y1> {
fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
Point {
x: self.x,
y: other.y,
}
}
}
fn main() {
let p = Point { x: 5, y: 10 };
println!("p.x = {}", p.x()); }
Traits
A trait defines functionality a particular type has and can share with other types. We can use traits to define shared behavior in an abstract way. We can use trait bounds to specify that a generic type can be any type that has certain behavior.
Trait example
pub trait Summary { fn summarize(&self) -> String; }
Implementing a Trait on a Type Example
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!(“{}, by {} ({})”, self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!(“{}: {}”, self.username, self.content)
}
}
use aggregator::{Summary, Tweet};
fn main() {
let tweet = Tweet {
username: String::from(“horse_ebooks”),
content: String::from(
“of course, as you probably already know, people”,
),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize()); }
Default Implementations
pub trait Summary {
fn summarize(&self) -> String {
String::from(“(Read more…)”)
}
}
Traits as Parameters
pub fn notify(item: &impl Summary) {
println!(“Breaking news! {}”, item.summarize());
}
trait bound
The impl Trait syntax works for straightforward cases but is actually syntax sugar for a longer form known as a trait bound; it looks like this:
pub fn notify<T: Summary>(item: &T) {
println!(“Breaking news! {}”, item.summarize());
}
Returning Types that Implement Traits
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,
}
}
dangling references
reference data other than the data it’s intended to reference
An attempt to use a reference whose value has gone out of scope
fn main() {
let r;
{ let x = 5; r = &x; } println!("r: {}", r); }
borrow checker
The Rust compiler has a borrow checker that compares scopes to determine whether all borrows are valid.
fn main() {
let r; // ———+– ‘a
// |
{ // |
let x = 5; // -+– ‘b |
r = &x; // | |
} // -+ |
// |
println!(“r: {}”, r); // |
} // ———+
Lifetime Annotation Syntax (‘)
Lifetime annotations don’t change how long any of the references live. Rather, they 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 for the first lifetime annotation. We place lifetime parameter annotations after the & of a reference, using a space to separate the annotation from the reference’s type.
&i32 // a reference
&’a i32 // a reference with an explicit lifetime
&’a mut i32 // a mutable reference with an explicit lifetime