liveBook · Manning

Blanket implementation

As explained in Idiomatic Rust

A blanket implementation is a trait implementation that applies to every type satisfying specified trait bounds.

A blanket implementation implements a trait for a family of types rather than one concrete type. Generic parameters describe the family; trait bounds decide which members qualify. Use one when the same behavior should apply across many eligible types, especially in a library where implementing each combination separately would be tedious. section 7.4

A bound supplies the behavior

`impl<T: Display> ToString for T { /* ... */ }` makes `ToString` available to any type that implements `Display`. By contrast, `impl<T> Blanket for T {}` covers every type without a bound. The syntax is simple; choosing useful bounds is the important part. section 7.4

An implementation can also be partially blanket: some parameters remain generic while others are fixed. In the `Buffer` conversion below, `Vec<T>` is the source, while both the element type `T` and buffer length `LENGTH` vary. `T` must implement `Default` and `Copy`; the conversion checks that the vector’s length matches `LENGTH` before copying its elements. The length check is an assertion, not a guarantee supplied by the trait bound. section 7.4

Listing 7.1 Blanket trait implementation with const generics
impl<T: Default + Copy, const LENGTH: usize> From<Vec<T>>
    for Buffer<T, LENGTH>
{
    fn from(v: Vec<T>) -> Self {
        assert_eq!(LENGTH, v.len());      #1
        let mut ret = Self {
            buf: [T::default(); LENGTH],
        };
        ret.buf.copy_from_slice(&v);      #2
        ret
    }
}

The `From<Vec<T>> for Buffer<T, LENGTH>` listing shows trait bounds, a const generic, the length assertion, and the element copy together. section 7.4

Blanket implementations can also turn a set of bounds into a marker trait. An empty `FullFeatured` trait can be implemented for every type meeting its listed bounds, then used as a single bound on a container. Keep the distinction clear: this marker records qualifying traits; it does not itself add methods. Blanket implementations are a specialized tool, not a reason to make every trait apply to every type. section 7.5 section 7.0

Listing 7.2 Full-featured marker trait
#[derive(
    Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
)]
struct KitchenSink;               #1

trait FullFeatured {}             #2

impl<T> FullFeatured for T where  #3
    T: Clone
        + Copy
        + std::fmt::Debug
        + Default
        + Eq
        + std::hash::Hash
        + Ord
        + PartialEq
        + PartialOrd
{
}

The marker-trait listing shows how one `where` clause grants `FullFeatured` to every type satisfying the complete set of bounds. section 7.5

How Idiomatic Rust covers it

How deep it goes
Works through generic syntax, trait bounds, partial implementations, and a const-generic conversion, including its runtime length assertion.
Examples
Uses `Display`-based `ToString`, `Vec<T>`-to-`Buffer<T, LENGTH>` conversion, and a `FullFeatured` marker trait.
What it assumes
Assumes familiarity with Rust traits and generics; builds on trait bounds and const generics rather than teaching Rust from zero.
What you can do after
Build it from scratch using bounded generic trait implementations for conversions or marker traits.
How it connects
Connects trait bounds and generics with const generics, conversion traits, and marker traits.

Also explained in

Compare how 3 books explain blanket implementation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Idiomatic Rust. The section links point to the parts of the book it draws on.