Search code examples
rustcloneflatmap

Is std::iter::FlatMap.clone() possible?


I am trying to create all possible pairs of items in a FlatMap:

possible_children.clone().flat_map(|a| possible_children.clone().map(|b| (a,b)))

In order to do this, I am trying to clone a FlatMap and I see in the documentation that the FlatMap struct implements a clone method. But it doesn't seem possible to create a FlatMap that satisfies the trait bounds.

This is the error I am getting:

error: no method named `clone` found for type `std::iter::FlatMap<std::ops::Range<u16>, _, [closure@src/main.rs:30:47: 33:27]>` in the current scope
  --> src/main.rs:37:66
   |
37 |         possible_children.clone().flat_map(|a| possible_children.clone().map(|b| (a,b)))
   |                                                                  ^^^^^
   |
   = note: the method `clone` exists but the following trait bounds were not satisfied: `[closure@src/main.rs:30:47: 33:27] : std::clone::Clone`

Looking at the documentation I see:

impl<I, U, F> Clone for FlatMap<I, U, F>
    where F: Clone, I: Clone, U: Clone + IntoIterator, U::IntoIter: Clone

and

impl<I, U, F> Iterator for FlatMap<I, U, F>
    where F: FnMut(I::Item) -> U, I: Iterator, U: IntoIterator

It looks like F is bound by both the Clone trait and the FnMut trait, but it is not possible for something to implement both FnMut and Clone.

It seems strange that a method would exist in the documentation that isn't possible to call, so I must be missing something.

Can someone please clarify for me?

MVCE:

fn main() {
    let possible_children = (0..10).flat_map(|x| (0..10).map(|y| (x,y)));

    let causes_error = possible_children.clone().flat_map(|a|
        possible_children.clone().map(|b| (a,b) )
    ).collect();

    println!("{:?}",causes_error);
}

Solution

  • There's no inherent reason that a type can't implement both FnMut and Clone, but it seems that at the moment closures don't implement Clone. Here's a brief discussion about this from 2015. I haven't (yet) found any more recent discussion.

    I was able to construct this example where a FlatMap is cloned by implementing FnMut on my own struct, which requires unstable features, so a nightly compiler (playground):

    #![feature(unboxed_closures)]
    #![feature(fn_traits)]
    struct MyFun {
        pub v: usize,
    }
    
    impl FnOnce<(usize,)> for MyFun {
        type Output = Option<usize>;
        extern "rust-call" fn call_once(self, args: (usize,)) -> Self::Output {
            Some(self.v + 1 + args.0)
        }
    
    }
    
    impl FnMut<(usize,)> for MyFun {
        extern "rust-call" fn call_mut(&mut self, args: (usize,)) -> Self::Output {
            self.v += 1;
            if self.v % 2 == 0 {
                Some(self.v + args.0)
            } else {
                None
            }
        }
    }
    
    impl Clone for MyFun {
        fn clone(&self) -> Self {
            MyFun{v: self.v}
        }
    }
    
    fn main() {
        let possible_children = (0..10).flat_map(MyFun{v:0});
        let pairs = possible_children.clone().flat_map(|x| possible_children.clone().map(move |y| (x,y) ) );
        println!("possible_children={:?}", pairs.collect::<Vec<_>>());
    }