Rust Higher-Rank Trait Bounds


Example

fn copy_if<F>(slice: &[i32], pred: F) -> Vec<i32>
    where for<'a> F: Fn(&'a i32) -> bool
{
    let mut result = vec![];
    for &element in slice {
        if pred(&element) {
            result.push(element);
        }
    }
    result
}

This specifies that the reference on i32 in the Fn trait bound can have any lifetime.

The following does not work:

fn wrong_copy_if<'a, F>(slice: &[i32], pred: F) -> Vec<i32>
    where F: Fn(&'a i32) -> bool
{                                   // <----------------+
    let mut result = vec![];        //       'a scope   |
    for &element in slice {         // <--------+       |
        if pred(&element) {         //          |       |
            result.push(element);   // element's|       |
        }                           //   scope  |       |
    }                               // <--------+       |
    result                          //                  |
}                                   // <----------------+

The compiler gives the following error:

error: `element` does not live long enough
if pred(&element) {         //          |       |
         ^~~~~~~

because the element local variable does not live as long as the 'a lifetime (as we can see from the code's comments).

The lifetime cannot be declared at the function level, because we need another lifetime. That's why we used for<'a>: to specify that the reference can be valid for any lifetime (hence a smaller lifetime can be used).

Higher-Rank trait bounds can also be used on structs:

struct Window<F>
    where for<'a> F: FnOnce(&'a Window<F>)
{
    on_close: F,
}

as well as on other items.

Higher-Rank trait bounds are most commonly used with the Fn* traits.

For these examples, the lifetime elision works fine so we do not have to specify the lifetimes.