I need to implement the method iter
, which returns something which implements the trait Iterator<Item = char>
. But the return value will be different implementations, depending on the enum variant.
Something like this:
pub enum Class {
SingleChar(char),
Range(Range),
And(Vec<Class>),
Or(Vec<Class>),
}
impl Class {
pub fn iter(&self) -> Iterator<Item = char> {
match *self {
Class::SingleChar(c) => vec![c],
Class::Range(ref range) => range.iter(),
Class::And(ref classes) => {
let iter: Option<_> = classes.iter().fold(None, |iter, &class| {
match iter {
None => Some(class.iter()),
Some(iter) => Some(iter.merge(class.iter())),
}
});
Box::new(iter.unwrap())
},
Class::Or(ref classes) => {
let iter: Option<_> = classes.iter().fold(None, |iter, &class| {
match iter {
None => Some(class.iter()),
Some(iter) => Some(iter.interleave(class.iter())),
}
});
Box::new(iter.unwrap())
},
}
}
}
range.iter()
returns a struct that implements Iterator<Item=char>
.
merge
and interleave
are itertools
methods, which return MergeAscend
and Interleave
respectively (both of them implement Iterator<Item=char>
)
It is not possible to do it using static dispatch. There is a tracking RFC issue on unboxed abstract return types, but Rust is not there yet (and I'm not sure if it could cover the use case of returning different types). Therefore, dynamic dispatch is the way to go.
You're pretty close, actually. Just make the return type Box<Iterator<Item=char>>
and add more boxing:
pub fn iter(&self) -> Box<Iterator<Item=char>> {
match *self {
Class::SingleChar(c) => Box::new(Some(c).into_iter()),
Class::Range(ref range) => Box::new(range.iter()),
Class::And(ref classes) => {
let iter: Option<_> = classes.iter().fold(None, |iter, &class| {
match iter {
None => Some(Box::new(class.iter())),
Some(iter) => Some(Box::new(iter.merge(class.iter()))),
}
});
iter.unwrap()
},
Class::Or(ref classes) => {
let iter: Option<_> = classes.iter().fold(None, |iter, &class| {
match iter {
None => Some(Box::new(class.iter())),
Some(iter) => Some(Box::new(iter.interleave(class.iter()))),
}
});
iter.unwrap()
},
}
}
This should work.