Traits

Blanket Implementations

A blanket implementation is a generic trait implementation of the form impl<T: Bound> Trait for T (or impl<T> Trait for &T) that implements a trait automatically for every type T that satisfies the specified bounds, rather than for a single named struct or enum.

Standard Library Blanket Implementations

Two of the most widely used trait implementations in Rust's standard library are blanket implementations:

1. ToString for Every T: Display

In alloc::string, the standard library defines:

// Conceptual definition in the standard library:
// impl<T: fmt::Display + ?Sized> ToString for T { ... }

Because of this blanket implementation, any type that implements std::fmt::Display automatically gains .to_string() without writing impl ToString for MyType.

2. Into<U> for Every T Where U: From<T>

In core::convert, the standard library defines:

// Conceptual definition in the standard library:
// impl<T, U> Into<U> for T where U: From<T> {
//     fn into(self) -> U { U::from(self) }
// }

Whenever you implement From<Source> for Target, the blanket implementation automatically provides Into<Target> for Source.

Writing a Custom Blanket Implementation

You can define your own trait and provide a blanket implementation so every type satisfying an existing bound gains your trait's methods automatically:

use std::fmt::Debug;

trait Inspectable {
    fn debug_type_and_value(&self) -> String;
}

// Blanket implementation for ALL types T that implement Debug:
impl<T: Debug> Inspectable for T {
    fn debug_type_and_value(&self) -> String {
        format!("{}: {:?}", std::any::type_name::<T>(), self)
    }
}

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    // Primitives, slices, and custom structs all get `debug_type_and_value()` automatically:
    println!("{}", 42_i32.debug_type_and_value());
    println!("{}", [1, 2, 3].debug_type_and_value());
    println!("{}", Point { x: 5, y: 9 }.debug_type_and_value());
}
i32: 42
[i32; 3]: [1, 2, 3]
 blank::Point: Point { x: 5, y: 9 }

Forwarding Blanket Implementations for References (&T and &mut T)

Library authors frequently write blanket implementations for shared or mutable references (impl<T: MyTrait + ?Sized> MyTrait for &T) so generic functions that accept T: MyTrait by value also work seamlessly when callers pass a reference &MyType:

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

// Forwarding blanket impl: if `T` is a `MetricSource`, then `&T` is also a `MetricSource`
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_metric<M: MetricSource>(source: M) {
    println!("Recorded sample: {:.2}", source.sample());
}

fn main() {
    let cpu = CpuLoad(0.73);
    // Works by reference (&CpuLoad) without consuming `cpu`:
    record_metric(&cpu);
    // And `cpu` can still be passed by value afterward:
    record_metric(cpu);
}
Recorded sample: 0.73
Recorded sample: 0.73

Coherence Restrictions on Blanket Implementations

Because impl<T: Bound> Trait for T covers every current and future type implementing Bound, two rules apply:

  1. Local trait requirement (E0210): You can only write a blanket implementation impl<T: ...> Trait for T if Trait is defined in your own crate.
  2. No overlapping concrete overrides (E0119): Once a crate defines impl<T: Display> MyTrait for T, no other impl MyTrait for ConcreteType can be written for any type that implements (or might later implement) Display.