Reputation: 766
What's the right way to return a boxed clonable iterator from an expression? For example:
fn example() -> Box<Iterator<Item = String> + Clone> {
unimplemented!()
}
This gives me an error that only automatic traits can be specified in this manner:
error[E0225]: only auto traits can be used as additional traits in a trait object
--> src/main.rs:1:47
|
1 | fn example() -> Box<Iterator<Item = String> + Clone> {
| ^^^^^ non-auto additional trait
This is my real code:
let my_iterator = {
if a {
Box::new(/* ... */) as Box<Iterator<Item = String> + Clone>
} else {
Box::new(/* ... */) as Box<Iterator<Item = String> + Clone>
}
};
let pb = ProgressBar::new(my_iterator.clone().count() as u64);
If alternative suggestions are considered: the two branches represent one path for loading from a file, the other path for generating automatically, and I'd rather not keep things in memory if they aren't needed.
Upvotes: 4
Views: 592
Reputation: 430891
Iterator
is a trait and thus Box<Iterator>
is a trait object.
Clone
cannot be made into a trait object because it requires knowledge of Self
, so we follow the instructions in How to clone a struct storing a boxed trait object?:
trait CloneIterator: Iterator {
fn clone_box(&self) -> Box<CloneIterator<Item = Self::Item>>;
}
impl<T> CloneIterator for T
where
T: 'static + Iterator + Clone,
{
fn clone_box(&self) -> Box<CloneIterator<Item = Self::Item>> {
Box::new(self.clone())
}
}
fn example(switch: bool) -> Box<CloneIterator<Item = String>> {
let i = vec!["a".into(), "b".into()].into_iter();
if switch {
Box::new(i)
} else {
Box::new(i.take(1))
}
}
fn main() {
let i = example(true);
let i2 = i.clone_box();
let j = example(false);
let j2 = j.clone_box();
}
See also:
Upvotes: 2