Module 7 • Lesson 38

Trait Bounds and Where Clauses

📚 9 min💻 Free🦀 nixus.pro

Trait Bounds and Where Clauses

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

// Inline bounds
fn print_if_positive(val: T) {
    if val > T::default() { println!("{}", val); }
}

// Where clause (cleaner for complex bounds)
fn compare_and_display(t: &T, u: &U) -> String
where
    T: Display + Debug + Clone,
    U: Display + PartialOrd,
{
    format!("t={:?} u={}", t, u)
}

// Multiple bounds with +
trait Printable: Display + Debug + Clone {}
impl Printable for T {}

// impl Trait in parameters (sugar for T: Trait)
fn notify(item: &impl Display) { println!("Breaking news! {}", item); }
// Equivalent to:
fn notify2(item: &T) { println!("Breaking news! {}", item); }

// impl Trait in return position
fn make_greeting(name: String) -> impl Display {
    format!("Hello, {}!", name)
}

// Conditional implementations
use std::fmt;
struct Wrapper(T);
impl fmt::Display for Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Wrapper({})", self.0)
    }
}
// Wrapper only implements Display if T: Display

fn main() {
    print_if_positive(5);
    print_if_positive(-3.0_f64); // Won't print
    notify(&"Hello");
    println!("{}", make_greeting("Rust".to_string()));
    println!("{}", Wrapper(42));
}

🎯 Practice

  1. Write fn largest_display<T>(v: &[T]) -> &T where T has appropriate bounds, and print it
  2. Write a generic struct Cache<K, V> that requires K: Hash + Eq and V: Clone
  3. Implement Display conditionally for a wrapper type only when the inner type is Display

🎉 Key Takeaways