liveBook · Manning

Trait bound

As explained in Idiomatic Rust

A trait bound is a constraint requiring a generic type to implement one or more specified traits.

A trait bound constrains a generic type parameter to types implementing a specified trait. It lets generic code rely on shared behavior without naming a concrete type: a function that calls `t.describe()` needs a bound promising that `T` provides `describe`. section 2.2.4 section 2.3

fn describe_type<T>(t: &T) -> String
where
    T: SelfDescribing,
{
    t.describe()
}

The `where T: SelfDescribing` clause makes `t.describe()` valid. For a short bound, `fn describe_type<T: SelfDescribing>(t: &T) -> String` expresses the same requirement inline; `where` can be easier to read when bounds grow. section 2.2.4

Without the bound, the compiler reports that `describe` is unavailable on `&T`. Adding the bound fixes the function definition, but callers must still supply a type implementing `SelfDescribing`; otherwise compilation fails at the call. section 2.2.4

#[derive(Clone)]
struct ListItem<T>
where
    T: Clone + Debug,
{
    data: Box<T>,
    next: Option<Box<ListItem<T>>>,
}

Bounds also apply to generic structs. Here `T: Clone + Debug` requires both traits for `ListItem<T>`. The `Clone` bound accompanies the struct’s derived `Clone` implementation. section 2.1.6

Choose a method in generic code

Suppose two traits implemented for one type both define `name`. Calling `container.name()` is ambiguous—even giving the methods different argument lists does not resolve it. Separate functions bounded by `T: First` and `T: Second` can call the intended trait method in each context. A generic `get_name<T>` with no bound cannot call `t.name()` at all. section 5.2.4

impl<T: Display> ToString for T {
    // ...
}

Bounds can govern implementations as well as functions. This blanket implementation provides `ToString` for any `T` implementing `Display`, rather than requiring a separate implementation for every qualifying type. section 7.4

Use a bound when generic code needs a trait’s behavior or when an implementation should apply only to qualifying types. A bound is a requirement, not an implementation: the required trait must still be implemented for each concrete type, unless an applicable blanket implementation supplies it. section 2.2.4 section 7.4

How Idiomatic Rust covers it

How deep it goes
Works through syntax and compiler errors, then applies bounds to method conflicts and blanket implementations.
Examples
Uses a linked-list item, a describing function, conflicting `name` methods, and the `Display`-to-`ToString` implementation.
What it assumes
Assumes familiarity with generic type parameters while introducing why a trait method needs an explicit bound.
What you can do after
Practice/perform it by adding Rust bounds that permit trait-method calls and restrict generic implementations.
How it connects
Connects generics and traits with method resolution, derived traits, and blanket implementations.

Also explained in

Compare how 2 books explain trait bound →

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.