Generics, Traits, and Lifetimes

Using generics

struct Point<T, U> { x: T, y: U, } impl<T, U> Point<T, U> { fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> { Point { x: self.x, y: other.y, } } }

Defining traits

trait Animal { fn new(name: &'static str) -> Self; fn noise(&self) -> &'static str { "" } } struct Dog { name: &'static str } impl Dog { fn fetch() { // ... } } impl Animal for Dog { fn new(name: &'static str) -> Dog { Dog { name: name } } fn noise(&self) -> &'static str { "woof!" } }

Default implementations with Derive

// A tuple struct that can be printed #[derive(Debug)] struct Inches(i32);

Trait bounds

fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { let mut largest = list[0]; for &item in list { if item > largest { largest = item; } } largest }

impl trait

fn make_adder_function(y: i32) -> impl Fn(i32) -> i32 { let closure = move |x: i32| { x + y }; closure }

Trait objects

pub struct Screen { pub components: Vec<Box<dyn Draw>>, }

Operator overloading

use std::ops::Add; #[derive(Debug, Copy, Clone, PartialEq)] struct Point { x: i32, y: i32, } impl Add for Point { type Output = Point; fn add(self, other: Point) -> Point { Point { x: self.x + other.x, y: self.y + other.y, } } }

Supertraits

use std::fmt; trait Log: fmt::Display { fn log(&self) { let output = self.to_string(); println!("Logging: {}", output); } }

Lifetimes in function signatures

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }

Lifetimes in struct definitions

struct User<'a> { full_name: &'a str, }

Static lifetimes

let s: &'static str = "Rust";