Advanced Lifetimes and Borrowing

for<'a> Bounds

Explicit for<'a> bounds are required whenever lifetime elision cannot infer a higher-ranked lifetime automatically—Specifically when applying higher-ranked bounds to custom traits (for<'a> T: CustomTrait<'a>), returning borrowed references tied to an input lifetime in a closure (for<'a> F: Fn(&'a T) -> &'a U), or requiring &'a self / &'a Container to implement IntoIterator for arbitrary borrow durations.

Custom Traits with for<'a> Bounds

Unlike Fn(&T), custom traits such as Deserialize<'de>, From<&'a [u8]>, or a custom Parser<'a> do not implicitly desugar elided lifetimes into for<'a>. You must write for<'a> explicitly in the where clause:

trait Extractor<'a> {
    type Output;
    fn extract(&self, line: &'a str) -> Self::Output;
}

struct FirstWordExtractor;

impl<'a> Extractor<'a> for FirstWordExtractor {
    type Output = &'a str;

    fn extract(&self, line: &'a str) -> Self::Output {
        line.split_whitespace().next().unwrap_or("")
    }
}

fn process_lines<E>(extractor: &E, lines: &[String])
where
    for<'a> E: Extractor<'a, Output = &'a str>,
{
    for line in lines {
        // `line` is borrowed for a distinct local iteration lifetime `'a`:
        let word: &str = extractor.extract(line);
        println!("extracted: {:?}", word);
    }
}

fn main() {
    let lines = vec![
        String::from("  rust 2024"),
        String::from("higher ranked bounds"),
    ];
    process_lines(&FirstWordExtractor, &lines);
}
extracted: "rust"
extracted: "higher"

Requiring Reference Iteration via for<'a> &'a C: IntoIterator

When writing a generic function that iterates over a collection C multiple times by reference without consuming C, writing where for<'a> &'a C: IntoIterator<Item = &'a T> expresses that borrowing C for any local lifetime 'a yields an iterator over &'a T:

use std::fmt::Display;

fn print_twice<C, T>(collection: &C)
where
    for<'a> &'a C: IntoIterator<Item = &'a T>,
    T: Display + 'static,
{
    print!("Pass 1: ");
    for item in collection {
        print!("{} ", item);
    }
    println!();

    print!("Pass 2: ");
    for item in collection {
        print!("{} ", item);
    }
    println!();
}

fn main() {
    let numbers = vec![10, 20, 30];
    print_twice(&numbers);
}
Pass 1: 10 20 30 
Pass 2: 10 20 30 

Guiding Closure Type Inference for Higher-Ranked Closures

When passing an inline closure |x| ... to a function expecting for<'a> Fn(&'a T) -> &'a U, omitting the type annotation on the closure parameter can sometimes cause the compiler to infer a single fixed lifetime instead of a higher-ranked closure. Annotating the closure parameter as |x: &str| (or using a helper funnel function) tells the compiler to synthesize a higher-ranked closure:

fn apply_slicer<F>(f: F)
where
    F: for<'a> Fn(&'a str) -> &'a str,
{
    let s = String::from("key=value");
    println!("sliced: {:?}", f(&s));
}

fn main() {
    // Explicit `: &str` annotation on the closure parameter ensures `for<'a>` inference:
    apply_slicer(|input: &str| input.split('=').nth(1).unwrap_or(""));
}
sliced: "value"