Associated Types and Advanced Traits

Blanket Implementations

A blanket implementation is a generic impl block that implements a trait for all types T (or all types matching a structural pattern like &T) that satisfy a specified set of trait bounds.

Anatomy of a Blanket Implementation

Instead of naming a concrete type after for, a blanket implementation introduces a type parameter on impl<T> and implements the trait for T:

impl<T: Bound> TargetTrait for T {
     ▲  ^^^^^  ^^^^^^^^^^^     ^
     │    │         │          └── implemented for every matching type T
     │    │         └───────────── the trait being implemented
     │    └─────────────────────── prerequisite bound on T
     └──────────────────────────── generic type parameter declaration
use std::fmt::Display;

trait JsonScalar {
    fn to_json_string(&self) -> String;
}

// Blanket implementation for every type T that implements Display:
impl<T: Display> JsonScalar for T {
    fn to_json_string(&self) -> String {
        format!("\"{self}\"")
    }
}

fn main() {
    println!("Integer: {}", 42.to_json_string());
    println!("Boolean: {}", true.to_json_string());
    println!("Str:     {}", "hello".to_json_string());
}
Integer: "42"
Boolean: "true"
Str:     "hello"

Key Blanket Implementations in the Standard Library

Blanket Implementation Provided By What It Unlocks
impl<T: Display + ?Sized> ToString for T alloc::string .to_string() on any type that implements Display
impl<T, U> Into<U> for T where U: From<T> core::convert .into() for every From implementation
impl<T, U> TryInto<U> for T where U: TryFrom<T> core::convert .try_into() for every TryFrom implementation
impl<I: Iterator> IntoIterator for I core::iter Using any Iterator directly in a for loop
impl<T: ?Sized> Borrow<T> for T core::borrow Every type borrows as itself (&T)

Forwarding Implementations Over References (&T and &mut T)

A related pattern implements a trait for &T or &mut T whenever T implements that trait, allowing generic functions to accept borrowed references by value without requiring callers to dereference:

trait MetricSource {
    fn sample(&self) -> f64;
}

// Forwarding blanket impl for shared references `&T`:
impl<T: MetricSource + ?Sized> MetricSource for &T {
    fn sample(&self) -> f64 {
        (**self).sample()
    }
}

struct CpuLoad(f64);

impl MetricSource for CpuLoad {
    fn sample(&self) -> f64 {
        self.0
    }
}

fn record(src: impl MetricSource) {
    println!("Sampled value: {:.2}", src.sample());
}

fn main() {
    let cpu = CpuLoad(0.73);
    record(&cpu); // Works with &CpuLoad via the forwarding blanket impl
    record(cpu);  // Also works with owned CpuLoad
}
Sampled value: 0.73
Sampled value: 0.73

Coherence Restrictions on Blanket Implementations

Because of the orphan and overlap rules:

  1. You can only write an uncovered blanket implementation impl<T: Bound> MyTrait for T for a trait MyTrait defined in your own crate. Attempting impl<T: MyBound> ForeignTrait for T fails with E0210.
  2. Once a trait has an open blanket implementation impl<T: Bound> MyTrait for T, no other impl MyTrait for ConcreteType can be added in the same or downstream crates, because ConcreteType could implement Bound now or in the future (E0119).