HRTB lifetime that spans multiple parameters

⚓ Rust    📅 2025-04-30    👤 surdeus    👁️ 4      

surdeus

Warning

This post was published 113 days ago. The information described in this article may have changed.

Hello. I found another lifetime puzzle while I was refactoring some tests. I have a generic Store type that can change based on a T type that I need to test. Creating T requires borrowing a Store, and T has an implicit internal lifetime.

In a perfect world, the make_t closure would use an internal HRTB to declare the T can't outlive the borrow of the Store. However, that isn't allowed.

Lifting up the lifetime to the outer function means that the lifetime now needs to last to the end of the function, so the owned Store within the function won't work anymore.

pub fn run_test<'a, T: 'a, Store: 'a> (
    make_store: impl Fn() -> Store,
    make_t: impl Fn(&'a Store) -> T,
    test_f: impl Fn(T),
) {
    let store = make_store();
    let t = make_t(&store);
    test_f(t);
}

fn main() {
    run_test(|| -> Vec<usize> {
        vec![42]
    },
    |store: &Vec<usize>| -> &Vec<usize> {
        store
    }, |_t| {});
}

I realize I can lift the creation of the Store outside the function (like this below), but I am hoping there is a solution that lets the closure reference a local variable within the outer function.

pub fn run_test<'a, T: 'a, Store>(
    store: &'a Store,
    make_t: impl Fn(&'a Store) -> T,
    test_f: impl Fn(T)
) {
    let t = make_t(store);
    test_f(t);
}

fn main() {
    let v = vec![42];
    run_test(&v,
    |store: &Vec<usize>| -> &Vec<usize> {
        store
    }, |_t| {});
}

Thanks for any thoughts.

3 posts - 2 participants

Read full topic

🏷️ rust_feed