Guide

Trait bounds

A plain T can be any type, so Rust lets you do almost nothing with it. A bound says which traits T must implement. Then you can use those traits' methods.

T: Trait

Write the bound after the type parameter.

use std::fmt::Display;fn show<T: Display>(x: T) {    println!("[{x}]");}

Display is the trait that {} uses to print a value. It lives in the standard library at std::fmt::Display. use std::fmt::Display; at the top lets you write just Display. Without the use, write the full path, like T: std::fmt::Display.

Now show accepts any type that implements Display. Join several bounds with +, like T: Display + Clone. Calling show with a type that is not Display fails with E0277.

Missing bounds

If the bound is missing, Rust will not guess.

You use on a TError without a bound
a + b or a > bE0369
a method like x.area()E0599
{} in println!E0277

Fix it by adding the bound, such as T: PartialOrd for >.

where clauses

Long bounds can move after the signature. These two mean the same thing:

fn f<T: Display + Clone>(x: T) {}fn f<T>(x: T)where    T: Display + Clone,{}

impl Trait arguments

impl Trait in an argument is a short way to write a bound.

fn show(x: impl Display) {    println!("[{x}]");}

impl Trait returns

-> impl Trait returns some type that implements the trait. The caller only knows the trait, not the real type.

fn label() -> impl Display {    42}

The function must return one single type. Returning an i32 in one branch and a &str in another fails with E0308.

Remember

  • Bounds unlock methods and operators on T.
  • where is only a different place to write bounds.
  • impl Trait is short for a bound in arguments and hides the real type in returns.