Nested iterators vs. lifetimes


#1

I’m trying to create a list of combinations from a list. This is simple in Haskell (or Python, or Clojure, or …). You just do something like:

λ> [(x, y) | x <- [0 .. 5], y <- [0 .. 5]]
[(0,0),(0,1),(0,2),(0,3),(0,4),(0,5),(1,0),(1,1),(1,2),(1,3),(1,4),(1,5),(2,0),(2,1),(2,2),(2,3),(2,4),(2,5),(3,0),(3,1),(3,2),(3,3),(3,4),(3,5),(4,0),(4,1),(4,2),(4,3),(4,4),(4,5),(5,0),(5,1),(5,2),(5,3),(5,4),(5,5)]

And other languages look similar. So I figured the rust equivalent would be something like:

fn main() {
    let v: Vec<usize> = vec![0, 1, 2, 3, 4, 5];
    let c = v.iter().flat_map(|x| v.iter().map(|y| (x.clone(), y.clone())))
        .collect::<Vec<(usize, usize)>>();
    println!("{:?}", c);
}

The calls to clone() deal with references popping out of the iterator. I suspect that’s the root of the problem, but haven’t been able to work around the error this gives me. Google hasn’t been much help, either.

But the error I get is a lifetime issue:

/tmp $ rustc test.rs 
test.rs:3:52: 3:78 error: `x` does not live long enough
test.rs:3         let c = v.iter().flat_map(|x| v.iter().map(|y| (x.clone(), y.clone())))
                                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~
test.rs:3:17: 4:46 note: reference must be valid for the method call at 3:16...
test.rs:3         let c = v.iter().flat_map(|x| v.iter().map(|y| (x.clone(), y.clone())))
test.rs:4             .collect::<Vec<(usize, usize)>>();
test.rs:3:39: 3:79 note: ...but borrowed value is only valid for the scope of parameters for function at 3:38
test.rs:3         let c = v.iter().flat_map(|x| v.iter().map(|y| (x.clone(), y.clone())))
                                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I’m a bit confused that it says ‘x’ does not live long enough. It points at y, and seems like y should be the problem.


#2
fn main() {
    let seq = (0..6)
        .flat_map(|x| (0..6)
            .map(move |y| (x, y))
        );
    println!("{:?}", seq.collect::<Vec<_>>());
}

The compiler is a bit lazy and captures x by reference; adding move to the innermost closure overrides this. If you’re dealing with a type that isn’t Copy, but is Clone, you can modify the inner map like so:

    .map({ let x = x.clone(); move |y| (x, y) })

#3

Very nice. Works great, and much cleaner than my attempt. Thank you.