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"