The idea is that I want the cartesian product of iterators that are all Box<dyn...>, because I have a function higher up that returns different types of iterators, some of which must be run through the cartesian product function. However, I'm having problems with the borrow checker given that Box<dyn ..> is not cloneable. Is there any way to get around this?
The code:
fn cartesian_product<'a>(iterators: &'a mut Vec<Box<dyn Iterator<Item = Sexp> + 'a>>) -> Box<dyn Iterator<Item = Vec<Sexp>> + 'a> {
if let Some(iter) = iterators.pop() {
let current_iterator = iter.map(|val| vec![val]);
let child_iterators = (Self::cartesian_product(iterators));
let combined_iterators = current_iterator.flat_map(move |vec| {
let val = child_iterators.map(move |item|
{
let mut vec_cloned = vec.clone();
let mut item_cloned = item.clone();
item_cloned.append(&mut vec_cloned);
item_cloned
});
val
});
Box::new(combined_iterators)
}
else {
Box::new(std::iter::empty())
}
}
The bug, currently:
cannot move out of `child_iterators`, a captured variable in an `FnMut` closure
move occurs because `child_iterators` has type `Box<dyn Iterator<Item = Vec<sexp::Sexp>>>`, which does not implement the `Copy` trait
I tried the above function, as well as a custom iterator that also has a hard time with the borrow checker.
To be clear, I don't want to call collect at any point.
There are many strategies that can be employed.
First, the probably most efficient way is to collect both iterators into
Vecs, theniter()it and callcartesian_product()on that. This won't work if the iterators are very big, however.In particular, only one iterator is required to be
Clone, so you can collect the shorter of them.Another strategy will be to have a custom trait that has
Iteratoras a supertrait but is also cloneable asdyn Trait. For how to do that, see How to clone a struct storing a boxed trait object?.