0Pricing
Learn Rust Coding · Lesson

Trait Bounds

Constrain generics with traits.

Trait Bounds is a free Learn Rust Coding lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Trait Bounds Do

A trait bound restricts a generic type to those that implement a given trait. It tells the compiler what behavior the type guarantees.

This unlocks the trait's methods inside the generic code while keeping the function usable for many types.

Inline Bound Syntax

The simplest form places the bound right after the type parameter: T: Trait. Here T must implement Display so it can be printed.

Inside the function you may now call any method that Display provides.

use std::fmt::Display;

fn show<T: Display>(value: T) {
    println!("value = {}", value);
}

A Custom Trait

Bounds work with your own traits too. Define a trait with a method, then bound a generic function by it.

This Summary trait requires a summarize method returning a string.

trait Summary {
    fn summarize(&self) -> String;
}

Implementing and Bounding

Implement the trait for a type, then a bounded function can accept any implementor. The function calls the trait method without knowing the concrete type.

This full program prints a summary of an Article.

trait Summary { fn summarize(&self) -> String; }

struct Article { title: String }

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("Article: {}", self.title)
    }
}

fn notify<T: Summary>(item: &T) {
    println!("{}", item.summarize());
}

fn main() {
    let a = Article { title: String::from("Rust") };
    notify(&a);
}

Combining Bounds With +

Require several traits at once by joining them with +. Here T must implement both Display and Clone.

The function can then print the value and also clone it.

use std::fmt::Display;

fn process<T: Display + Clone>(value: T) {
    let copy = value.clone();
    println!("{}", copy);
}

impl Trait in Arguments

The impl Trait syntax in an argument position is shorthand for a simple bound. item: &impl Summary means the same as a <T: Summary> parameter.

It is concise for single-argument cases but offers less control when you reuse the type.

trait Summary { fn summarize(&self) -> String; }

fn notify(item: &impl Summary) {
    println!("{}", item.summarize());
}

Returning impl Trait

You can also return impl Trait to hide a concrete type while promising it implements a trait. This is handy for closures and iterators.

The caller knows only that the result implements the named trait.

fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
    move |x| x + n
}

fn main() {
    let add5 = make_adder(5);
    println!("{}", add5(10));
}

Bounds Enable Operators

Operators map to traits: + needs Add, == needs PartialEq, comparisons need PartialOrd. Bounding by these lets generic code use the operators.

Here summing requires that T implement Add with itself.

use std::ops::Add;

fn sum<T: Add<Output = T>>(a: T, b: T) -> T {
    a + b
}

Default Trait Methods

Traits can provide default method bodies. Implementors may override them or rely on the default. Bounded generics use whichever is in effect.

This Summary has a default summarize that types can keep as-is.

trait Summary {
    fn summarize(&self) -> String {
        String::from("(no summary)")
    }
}

struct Note;
impl Summary for Note {}

Static vs Dynamic Dispatch

Trait bounds use static dispatch: the compiler picks the exact method at compile time via monomorphization. By contrast dyn Trait uses dynamic dispatch through a vtable.

Bounds are usually faster; dyn trades speed for smaller binaries and runtime flexibility.

Bounds on Generic Structs

Trait bounds are not limited to functions. You can require them when defining a struct so all instances satisfy the trait.

Here every Sortable<T> guarantees its items can be compared.

struct Sortable<T: PartialOrd> {
    items: Vec<T>,
}

Quick Check

Test your understanding of trait bounds.

Recap

Trait bounds constrain generic types so the compiler permits the trait's methods and operators. Combine traits with +, and use impl Trait as shorthand in arguments or returns.

Bounds give static dispatch with zero overhead, unlike dyn Trait dynamic dispatch.

Frequently asked questions

Is the “Trait Bounds” lesson free?

Yes — the full text of “Trait Bounds” is free to read here on the web, and the Learn Rust Coding course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.

What will I learn in “Trait Bounds”?

Constrain generics with traits. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Learn Rust Coding?

No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Trait Bounds” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Learn Rust Coding lesson?

Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Generic Functions
  2. Generic Structs and Enums
  3. Trait Bounds
  4. where Clauses and Multiple Bounds
← Back to Learn Rust Coding