Which is the best way to return different types of iterator when you need to apply some different adapters over a container?
For example depending suppose that because of some internal conditions you may need to filter or tochain and then return its result.
I would like to avoid creating a Vec where pushing all elements and returning it.
struct QuadTree {
data: Vec<i32>,
children: Vec<QuadTree>,
subdivided: bool,
}
impl QuadTree {
fn filter(&self, min: i32) -> impl Iterator<Item = &i32> {
if !self.subdivided {
self.data
.iter()
.filter(move |&&d| d >= min)
} else {
let mut v = core::iter::Filter::empty::<i32>(); // <-- This is not compiling
// Anyway I am wondering if this
// would be a good approach.
for q in &self.children {
v.chain(q.filter(min));
}
v
}
}
}
fn main() {
}
It doesn't compile because impl Trait must stand in for a single static type, but you effectively want dynamic typing here.
You can either return a Box<dyn Iterator<Item = …>>, or keep the impl Iterator and realize the dynamism by returning an enum for which you implement Iterator manually, by matching on it. If you only need a dichotomous decision, you can use the either crate.
Normally, I'd suggest the either crate (which @H2CO3 mentioned), but it runs into problems here due to the recursion: The non-leaf case has a static type dependent on the total recursion depth, so you have to insert a Box<dyn ...> anyway for that side to compile.
Anyway (it is a little out of topic) I have not fully understood why you have to specify the anonymous lifetime in dyn '_ + ..., I am checking the error, but it's not clear to me if it is because of the reference in the associated type Item = &i32 or because of the generic type of the Box itself (so the dyn argument)
Every type has a lifetime; it's just when you have a trait object, its actual underlying type is not known to the outside world, hence something at the interface boundary has to indicate what the lifetime/validity of the underlying type is. This depends purely on the lifetimes of the references the type holds (contains), and not on the interface of any of its methods.