Part 2 · 1 chapters · ~8 min
Traits and Generics
Defining and implementing traits, generics with trait bounds and where clauses, monomorphisation and static dispatch, trait objects and dynamic dispatch, derive, standard traits (From, Display, Iterator, Default), closures and the Fn traits, iterators, newtypes and making invalid states unrepresentable.
5
Traits and newtypes
code
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Kobo(i64);
impl std::ops::Add for Kobo { type Output = Kobo; fn add(self, o: Kobo) -> Kobo { Kobo(self.0 + o.0) } }
impl std::fmt::Display for Kobo {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "₦{}.{:02}", self.0 / 100, self.0 % 100) }
}
pub trait Rail { async fn submit(&self, payout: &Payout) -> Result<RailStatus, RailError>; } // async fn in traits (1.75+)
fn total<I: IntoIterator<Item = Kobo>>(xs: I) -> Kobo { xs.into_iter().fold(Kobo(0), |a, b| a + b) }
// state machine where illegal transitions do not compile: typestate
struct Payout<S> { id: String, state: S }
struct Reserved; struct Submitted; struct Completed;
impl Payout<Reserved> { fn submit(self) -> Payout<Submitted> { Payout { id: self.id, state: Submitted } } }
impl Payout<Submitted> { fn complete(self) -> Payout<Completed> { Payout { id: self.id, state: Completed } } }
// Payout<Reserved>::complete() does not exist: skipping submission is a compile errorTRAITS, GENERICS AND ZERO-COST ABSTRACTION
behaviour without inheritance
swipe the figure sideways, or tap expand for full screen
1/6
traits
Traits define shared behaviour, like interfaces, but implemented separately from the type (impl Notifier for SmsClient), even for types from other crates within the orphan rules.
behaviour defined separately from dataimpl Trait for Type