Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Rust Dictionary

  1. Home
  2. Rust Dictionary
  3. Combining Generics and Trait Bounds

Combining Generics and Trait Bounds

Since: Rust 1.0(2015)

A trait bound specifies, using a trait, the constraints that a generic type parameter must satisfy. This guarantees at compile time that a type has certain methods or capabilities.

Syntax

// Basic trait bound (trait name after :)
fn function_name<T: TraitName>(arg: T) { ... }

// Requiring multiple traits (combined with +)
fn function_name<T: Clone + Debug>(arg: T) { ... }

// where clause syntax (cleaner for complex bounds)
fn function_name<T, U>(a: T, b: U)
where
    T: Clone + Debug,
    U: Display + PartialOrd,
{ ... }

// impl Trait syntax (shorthand for arguments and return types)
fn function_name(arg: impl TraitName) -> impl TraitName { ... }

Syntax Reference

SyntaxDescription
<T: Trait>Specifies a trait bound on the type parameter T.
<T: A + B>Requires the type to implement multiple traits at once.
where T: TraitWrites the bound on a separate line using a where clause. Makes complex conditions easier to read.
impl TraitShorthand syntax usable as an argument or return type. Equivalent to an anonymous type parameter.
dyn TraitDynamic dispatch (trait object). Resolves methods at runtime.

Sample Code

sample_generics_trait_bound.rs
use std::fmt::{Debug, Display};

// Multiple trait bounds: requires both Clone and Debug.
fn print_twice<T: Clone + Debug>(item: T) {
    let copy = item.clone();
    println!("{:?} / {:?}", item, copy);
}

// where clause: improves readability when there are two or more parameters.
fn compare_and_show<T, U>(a: T, b: U) -> String
where
    T: Display + PartialOrd,
    U: Display,
{
    format!("a={}, b={}", a, b)
}

// impl Trait syntax: returns a type that implements the trait.
fn make_adder(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

fn main() {
    print_twice(vec![1, 2, 3]); // [1, 2, 3] / [1, 2, 3]

    let result = compare_and_show(42, "hello");
    println!("{}", result); // a=42, b=hello

    let add5 = make_adder(5);
    println!("{}", add5(10)); // 15
}

Compile with the following command:

rustc generics_trait_bound.rs
./generics_trait_bound
[1, 2, 3] / [1, 2, 3]
a=42, b=hello
15

Common Mistakes

Common mistake 1: compile error from insufficient trait bounds

If you use a method or operator on a type parameter without listing the required trait as a bound, the compiler reports an error and tells you which trait is needed.

// Compile error: `T` doesn't implement `std::fmt::Display`
// fn print_val<T>(val: T) {
//     println!("{}", val);
// }

The same logic can also be written as:

use std::fmt::Display;

// Add the Display bound
fn print_val<T: Display>(val: T) {
    println!("{}", val);
}

fn main() {
    print_val(42);
    print_val("hello");
}

Common mistake 2: trying to return different types with impl Trait

impl Trait in a return position means the function returns exactly one concrete type (determined at compile time). To return different concrete types at runtime, use Box<dyn Trait>.

use std::fmt::Display;

// Compile error: mismatched types — impl Trait must be one concrete type
// fn make_display(flag: bool) -> impl Display {
//     if flag { 42 } else { "hello" }
// }

The same logic can also be written as:

use std::fmt::Display;

// Use Box<dyn Trait> to return different types at runtime
fn make_display(flag: bool) -> Box<dyn Display> {
    if flag {
        Box::new(42_i32)
    } else {
        Box::new("hello")
    }
}

fn main() {
    println!("{}", make_display(true)); // 42
    println!("{}", make_display(false)); // hello
}

Overview

Trait bounds let you guarantee at compile time that a generic type parameter supports certain methods. If you pass a type that does not satisfy the bounds, the compiler produces an error, preventing runtime failures.

When the number of bounds grows, function signatures can become hard to read. In that case, it is common practice to use a where clause to organize the bounds on separate lines.

When using impl Trait as a return type, the returned type must be a single, fixed type. If you need to return different types that implement a trait depending on a condition, use Box<dyn Trait> (dynamic dispatch) instead.

If you find any errors or copyright issues, please .