Course contentsShow
← Rust
Lesson 241 of 1,9103. Borrowing and ReferencesFree lesson

Higher-Rank Trait Bounds

Use HRTBs to handle lifetimes that must work for any provided input lifetime.

In this lesson, you will learn how to write trait bounds that allow a function to accept references with any lifetime, solving tricky borrow checker conflicts.

The Problem: Fixed Lifetimes

So far, when we use lifetimes, we usually fix them to a specific scope. For example, if you write fn process<'a>(input: &'a str), the compiler expects the caller to provide a reference that lives for exactly that specific 'a.

But what if you have a function that needs to work with a closure or a trait that takes a reference? If you try to pass a reference into that closure, the compiler often struggles to verify that the reference is valid for all the various lifetimes the closure might be called with.

Enter Higher-Rank Trait Bounds (HRTB)

Sometimes, you don't want to tie your code to one specific lifetime. You want to say: "This function works for any lifetime the caller provides."

We represent this using the for<'a> syntax. This is called a Higher-Rank Trait Bound. It tells the compiler to check the trait implementation for all possible lifetimes, rather than just one specific one.

Consider this snippet:

fn execute_callback<F>(callback: F) 
where 
    F: for<'a> Fn(&'a str) 
{
    let data = String::from("Hello!");
    callback(&data);
}

By using for<'a> Fn(&'a str), we are promising that our callback is flexible. It doesn't care if the string is borrowed for a short time or a long time; it can handle any &str reference that comes its way. Without the for<'a> syntax, the compiler might get confused, thinking the closure only works for one specific, rigid lifetime, which leads to "lifetime mismatch" errors when you try to pass local variables into it.

Why use this?

HRTBs are most common when working with closures or trait objects that need to accept references as arguments. They provide a way to express "universality" across lifetimes. Instead of fighting the borrow checker to force a reference to fit a single, predefined lifetime, you declare that your code is truly generic over time.

Key Takeaway: Higher-Rank Trait Bounds use the for<'a> syntax to declare that a trait implementation must hold true for all possible lifetimes, enabling flexible, reusable APIs.