A simple lifetime question


#1

I have the following code, why the first one is wrong?

Since the data is moved, it can be used in the reduce_move function, but the compiler given the error: "data does not live long enough "


// error
fn reduce_move<'a, F>(data: Vec<i32>, f: F) where F: FnMut(i32, &'a i32) -> i32 {
    let result = data.iter().fold(0i32, f);
    
    println!("{:?}", result);
}


// right
fn reduce_ref<'a, F>(data: &'a Vec<i32>, f: F) where F: FnMut(i32, &'a i32) -> i32 {
    let result = data.iter().fold(0i32, f);
    
    println!("{:?}", result);
}

    
fn main() {
    let a: Vec<i32> = vec![1, 2, 3];  
    let f = |x, y| x + y;
        
    reduce_move(a, f);
    //reduce_ref(&a, f);   
}


#2

Because 'a is selected by the caller. No matter what it picks, it must pick a lifetime that lives longer than the call to reduce_move. data, by virtue of being moved into reduce_move, cannot possibly live longer than the call to reduce_move. Thus, you are trying to create a borrow into data that lives longer than data does; this is impossible and the compiler rightly rejects your code.

You can fix this by just not specifying the lifetime yourself and letting the compiler handle it:

fn reduce_move<F>(data: Vec<i32>, f: F) where F: FnMut(i32, &i32) -> i32 {
    let result = data.iter().fold(0i32, f);
    println!("{:?}", result);
}

fn main() {
    let a: Vec<i32> = vec![1, 2, 3];
    reduce_move(a, |x, y| x + y);
}

#3

Thanks!

I thought the lifetime of 'a is the same lifetime as the reduce_move, rather than specified by the caller, so I thought data live as long as'a.


#4

And for those who wonder how you would write the lifetimes explicitly here:

fn reduce_move<F>(data: Vec<i32>, f: F) where F: for<'a> FnMut(i32, &'a i32) -> i32