0Pricing
Learn Rust Coding · Lesson

where Clauses and Multiple Bounds

Keep complex signatures readable.

where Clauses and Multiple Bounds is a free Learn Rust Coding lesson on CoddyKit — lesson 4 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.

When Inline Bounds Get Crowded

Inline bounds like <T: Display + Clone, U: Debug + Default> become hard to read as they grow. Rust offers the where clause as a cleaner alternative.

It moves the constraints below the signature, keeping the parameter list short.

Basic where Clause

A where clause sits between the return type and the body. Each line lists a type and its bounds.

These two signatures mean exactly the same thing; the where form just reads better.

use std::fmt::Display;

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

Multiple Bounds in where

You can place several constraints, one per type parameter, separated by commas. Each may combine traits with +.

This keeps a busy signature legible compared to cramming everything inline.

use std::fmt::{Display, Debug};

fn report<T, U>(a: T, b: U)
where
    T: Display + Clone,
    U: Debug,
{
    println!("{} {:?}", a, b);
}

A Complete Example

This program uses a where clause requiring Display. It runs and prints each argument with a label.

Notice how the function header stays clean even with the bound attached.

use std::fmt::Display;

fn label<T>(name: &str, value: T)
where
    T: Display,
{
    println!("{} = {}", name, value);
}

fn main() {
    label("age", 30);
    label("city", "Oslo");
}

Bounds Compiler Cannot Inline

Some bounds can only be written in a where clause, such as those on associated or referenced types. Inline syntax cannot express where Vec<T>: Clone.

The where form is therefore strictly more expressive.

fn duplicate<T>(items: Vec<T>) -> (Vec<T>, Vec<T>)
where
    Vec<T>: Clone,
{
    (items.clone(), items)
}

Combining Standard Traits

A common real-world bound mixes ordering, copying, and printing. This generic max_of finds the largest item in a slice.

The where clause groups all three traits the algorithm relies on.

use std::fmt::Display;

fn max_of<T>(items: &[T]) -> &T
where
    T: PartialOrd + Display,
{
    let mut best = &items[0];
    for item in items {
        if item > best { best = item; }
    }
    best
}

Running max_of

Here is the same idea in a runnable program. The slice of integers satisfies PartialOrd + Display, so the call compiles and prints the maximum.

The function would work equally well on floats or characters.

fn max_of<T>(items: &[T]) -> &T
where
    T: PartialOrd,
{
    let mut best = &items[0];
    for item in items {
        if item > best { best = item; }
    }
    best
}

fn main() {
    let nums = [3, 7, 1, 9, 4];
    println!("{}", max_of(&nums));
}

where on impl Blocks

where clauses also attach to impl blocks. This adds a method only when the stored type implements Display.

Instances whose T is not Display simply will not have this method.

use std::fmt::Display;

struct Holder<T> { item: T }

impl<T> Holder<T>
where
    T: Display,
{
    fn print(&self) {
        println!("{}", self.item);
    }
}

Many Bounds at Once

Real generic APIs often require several traits per parameter. This signature demands cloning, debugging, and a default value.

The where clause keeps it readable despite three bounds on one type.

use std::fmt::Debug;

fn build<T>() -> T
where
    T: Default + Clone + Debug,
{
    let v = T::default();
    v.clone()
}

Choosing Inline vs where

Use inline bounds for one or two simple constraints. Switch to where when there are many parameters, long trait lists, or bounds on complex types.

Both compile to identical code; the choice is purely about readability.

where With Lifetimes

A where clause can list lifetime relationships alongside trait bounds. This keeps generic signatures with both kinds of constraint organized.

Here the clause requires T to outlive the lifetime 'a.

fn keep<'a, T>(value: &'a T) -> &'a T
where
    T: 'a,
{
    value
}

Quick Check

Test your understanding of where clauses and multiple bounds.

Recap

A where clause moves trait bounds below the signature, improving readability when parameters or trait lists grow. It can also express bounds on complex types and lifetimes that inline syntax cannot.

Inline and where bounds compile identically, so pick whichever reads more clearly.

Frequently asked questions

Is the “where Clauses and Multiple Bounds” lesson free?

Yes — the full text of “where Clauses and Multiple 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 “where Clauses and Multiple Bounds”?

Keep complex signatures readable. 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 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “where Clauses and Multiple 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