0
votes

I want to write a function that process some slices in different order, so I decided to write a function that is generic over the iterating order, something like:

fn foo<'a, I: Iterator<Item = &'a mut i32>>(make_iter: impl Fn(&'a mut [i32]) -> I) {
    let mut data = [1, 2, 3, 4];

    make_iter(&mut data);
}

fn main() {
    foo(|x| x.iter_mut());
    foo(|x| x.iter_mut().rev());
}

This causes “borrowed value does not live long enough” error.

I imagine something like

fn foo(make_iter: impl for<'a> Fn(&'a mut [i32]) -> impl Iterator<Item = &'a mut i32>) {
    let mut data = [1, 2, 3, 4];

    make_iter(&mut data);
}

should be used, but impl Iterator is not allow at that position. So is there anything I can do?

Update:

The slices to to processed should be considered dynamically generated inside the foo function, and are dropped after processing.

2

2 Answers

0
votes

Your function is mostly correct. The compiled error "borrowed value does not live long enough" is due to the fact that you are defining your data inside the foo rather than pass it in. The error is because of the linelet mut data = [1, 2, 3, 4];

The life time of the data is same as the function foo because it is created in the function foo. However, the closure's life time is longer than the variable data as the closure is passed in as an argument to foo so its lifetime is longer than data. When the function foo goes out of the scope, the data is dropped. Then your closure's is trying to return a reference data which is already dropped. This is why you have compiled error "borrowed value does not live long enough".

You can make this compile by passing the data into foo as an argument, in this case, you will not have the issue due to lifetime.

The below code will compile.

fn foo<'a, I: Iterator<Item = &'a mut i32>>(make_iter: impl Fn(&'a mut [i32]) -> I, data: &'a mut Vec<i32>) {
    // let mut data = [1, 2, 3, 4];

    make_iter(data);
}

fn main() {
    let mut data= vec![1,2,3,4];
    foo(|x| x.iter_mut(), &mut data);
    foo(|x| x.iter_mut().rev(), &mut data);
}

The rustplay ground link : https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8b263451fcb01518b3f35bda8485af9c


Update: Sry to misunderstand your requirements. I was trying to come out a clean way to write this, but the best I can come up with is using Box<dyn to do. I know there are runtime cost for Box<dyn..., but I can't come out a better way using impl Iterator

The implementation using Box<dyn ... is

fn foo<F>(make_iter: F) where for<'a> F: Fn(&'a mut [i32])->Box<dyn Iterator<Item=&'a mut i32>+'a>{
    let mut data = vec![1, 2, 3, 4];

    make_iter(&mut data);
}


fn main() {
    foo(|x| Box::new(x.iter_mut()));
    foo(|x| Box::new(x.iter_mut().rev()));
}
0
votes

I came up with one solution:

use std::iter::Rev;
use std::slice::IterMut;

trait MakeIter<'a> {
    type Iter: Iterator<Item = &'a mut i32>;

    fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter;
}

fn foo(mut make_iter: impl for<'a> MakeIter<'a>) {
    let mut data = [1, 2, 3, 4];

    make_iter.make_iter(&mut data);
}

struct Forward;

impl<'a> MakeIter<'a> for Forward {
    type Iter = IterMut<'a, i32>;

    fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter {
        slice.iter_mut()
    }
}

struct Backward;

impl<'a> MakeIter<'a> for Backward {
    type Iter = Rev<IterMut<'a, i32>>;

    fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter {
        slice.iter_mut().rev()
    }
}

fn main() {
    foo(Forward);
    foo(Backward);
}

But I am not sure whether it can be simplified.

Update

Here is a simplification:

trait MakeIter<'a> {
    type Iter: Iterator<Item = &'a mut i32>;

    fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter;
}

fn foo(mut make_iter: impl for<'a> MakeIter<'a>) {
    let mut data = [1, 2, 3, 4];

    make_iter.make_iter(&mut data);
}

impl<'a, F, R> MakeIter<'a> for F
where
    F: FnMut(&'a mut [i32]) -> R,
    R: Iterator<Item = &'a mut i32>,
{
    type Iter = R;

    fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter {
        self(slice)
    }
}

fn iter_forward(slice: &mut [i32]) -> impl Iterator<Item = &mut i32> {
    slice.iter_mut()
}

fn iter_backward(slice: &mut [i32]) -> impl Iterator<Item = &mut i32> {
    slice.iter_mut().rev()
}

fn main() {
    foo(iter_forward);
    foo(iter_backward);
}