Course contentsShow
← Rust
Lesson 539 of 1,9105. Type System and TraitsFree lesson

Working with Multi-Trait Bounds

Compose requirements using intersection bounds to narrow the scope of generic functions.

In this lesson, you will learn how to refine your generic functions by requiring a type to satisfy multiple trait requirements simultaneously using intersection bounds.

Combining Requirements

Sometimes, a generic function needs more than just one capability from a type. For example, if you are building a data processing system, you might need a type to be both Clone (so you can create copies) and Display (so you can print the values to a log).

In Rust, you express these multiple requirements by combining traits with the + operator. This creates a "multi-trait bound," which tells the compiler: "I will only accept a type if it implements every single one of these traits."

The Syntax in Action

You can apply these bounds directly in your generic function signatures. Here is how it looks:

use std::fmt::Display;

// This function only accepts types that are both Clone AND Display
fn process_and_report<T: Clone + Display>(item: T) {
    let copy = item.clone();
    println!("Processing: {}", copy);
}

By using T: Clone + Display, you narrow the scope of T. If you passed a type that only implemented Display but not Clone, the Rust compiler would stop you with an error. This is a powerful way to ensure your code has exactly the functionality it needs to execute safely.

Why Use This?

Multi-trait bounds keep your code clean and expressive. Instead of writing complex internal logic to check if a type is capable of a specific action, you define those expectations upfront in the signature. This "intersection" approach allows you to build highly specific generic interfaces while keeping your code flexible enough to handle any type that meets the cumulative requirements.

If your generic constraints become long or difficult to read, remember that you can also move these bounds into a where clause to keep your function signature tidy. The logic remains the same: the type must satisfy the intersection of all listed traits.

Key Takeaway: Use the + operator within your generic bounds to require a type to satisfy multiple trait interfaces simultaneously, ensuring your functions have access to all the specific behaviors they need.