Segregated copy for nested closures

Viewed 126

I looked for similar questions like this one but it seems they are always different enough. I'm trying to compile (a more complex version of) this piece of code:

let vec: Vec<f64> = ⋯;
let length = ⋯;
let iterator = (0usize..length)
    .flat_map(|i| (0usize..length).map(|j| vec[(i + j) % vec.len()]));

but I get this ownership error:

error[E0373]: closure may outlive the current function, but it borrows `i`, which is owned by the current function
  --> tests\test.rs:19:45
   |
19 |         .flat_map(|i| (0usize..length).map(|j| vec[(i + j) % vec.len()]));
   |                                            ^^^      - `i` is borrowed here
   |                                            |
   |                                            may outlive borrowed value `i`
   |

I do not want to take ownership of vec so none of my closures should be move. It seems to me that theoretically i could be copied inside (0usize..length).map(|j| vec[(i + j) % vec.len()]) but because of vec it is only borrowed. As far as I know it may not be possible to tell rustc to borrow some variables and to copy others (Or is it?)

Changing the inner closure to (0usize..length).map(|j| vec[(i + j) % vec.len()]).collect::<Vec<_>>() solves the issue. Unfortunately it implies multiple memory allocation I would like to avoid as they seem totally unnecessary.

As a clarification this example is intended to be generated by a macro. In the general case it may generate an arbitrary number of nested levels and involve an arbitrary number of vectors to borrow:

let vec: Vec<f64> = ⋯;
let vec2: Vec<Vec<Vec<f64>>> = ⋯;
let length = ⋯;
let iterator = (0usize..length)
    .flat_map(|i| (0usize..length)
        .flat_map(|j| (0usize..length)
            .map(|k| vec[(i + j + k) % vec.len()] + vec2[i][j][k]));
1 Answers

You must use move to avoid the issue with i. If you don't want to move the vec into the closure, you can take a reference to it first and move that into the closure:

let iterator = (0usize..length)
    .flat_map (|i| {
        let vec = &vec[..];
        (0usize..length).map(move |j| vec[(i + j) % vec.len()])
    });

Playground

Related