rustlifetimeborrow-checkerborrowingborrow

ref to 'static does not live long enough?


Consider next code:

fn get_ref<'a, R>(slice: &'a Vec<i32>, f: fn(&'a Vec<i32>) -> R) -> R
where
    R: 'a,
{
    f(slice)
}

fn main() {
    let v = [1,2,3,4,5,6];
    let iter = get_ref(&v, |x| x.iter().skip(1).take(2));

    println!("{:?}", iter.collect::<Vec<_>>());
}

I create some static variable, then apply some function to its reference and get a result. It seems to work totally fine. At least it successfully compiles.

Now I am trying to add next level of abstraction. And things are getting weird...

fn owned<'a, R>(owner: Vec<i32>, f: fn(&'a Vec<i32>) -> R)
where
    R: 'a,
{
    let _ = get_ref(&owner, f); // error occurs here
    // `owner` does not live long enough.
}

// get_ref is the same as in the first example
fn get_ref<'a, R>(slice: &'a Vec<i32>, f: fn(&'a Vec<i32>) -> R) -> R
where
    R: 'a,
{
    f(slice)
}

fn main() {
    let v = [1,2,3,4,5,6];
    owned(v, |x| x.iter().skip(1).take(2));
}

For me it looks like pretty the same code. But Rust fails to compile it. I really don't understand why this is happening and how should I rewrite my code to compile.


Solution

  • Imagine if I decide to call the function owned<'static, i32>(Vec<i32>, foo) with foo defined as:

    fn foo(vec: &'static Vec<i32>) -> i32 { ... }
    

    This satisfies the bounds for owned, since i32: 'static. However this means that you must have a static reference to call f, but owner does not live forever, since it is destroyed at the end of owned.

    One way to fix it is to use the following:

    fn owned<R>(owner: Vec<i32>, f: for<'a> fn(&'a Vec<i32>) -> R) {
        let _ = get_ref(&owner, f);
    }
    

    It says that f must be callable with any lifetime, rather than just some specific lifetime. However, this has the consequence that R cannot borrow from the argument, since R is declared in a larger scope than 'a. There isn't any way to fix that while keeping the generics as is.


    This answer was taken from my response to this thread on URLO.