In the following code, the trait called LimitCollection has a function that returns a type that implements Iterator trait.
struct Limit {}
impl Limit {
fn is_violated(&self) -> bool {
todo!()
}
}
trait LimitCollection {
fn get_violated_limits<'a, I>(&'a self) -> I
where
I: Iterator<Item = &'a Limit>;
}
Now I'd like to make something that implements the trait but the compiler complains that there is mismatch between the type that I return and the generic return type: "expected type parameter I
, found struct Filter
"
struct ConcreteLimitCollection {
limits: Vec<Limit>,
}
impl LimitCollection for ConcreteLimitCollection {
fn get_violated_limits<'a, I>(&'a self) -> I
where
I: Iterator<Item = &'a Limit>,
{
self.limits.iter().filter(Limit::is_violated)
}
}
Is there any way to make this construct work, preferably without resorting to dynamic allocation?
Usually you would use an associated type , in this case we would have some lifetimes involved (we need a GAT, generic associated type). Sadly what it is needed is not stabilized yet:
#![feature(generic_associated_types)]
struct Limit {}
impl Limit {
fn is_violated(&self) -> bool {
todo!()
}
}
trait LimitCollection {
type Output<'a>: Iterator<Item = &'a Limit> where Self: 'a;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a>;
}
struct ConcreteLimitCollection {
limits: Vec<Limit>,
}
impl LimitCollection for ConcreteLimitCollection {
type Output<'a> = Box<dyn Iterator<Item = &'a Limit> + 'a> where Self: 'a;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a> {
Box::new(self.limits.iter().filter(|l| l.is_violated()))
}
}
Disclaimer, I used Box<dyn Iterator<Item = &'a Limit> + 'a>
even if you did not wanted to use dinamic allocation, but in this case you would just have to fulfill the whole Filter<...>
type. Just did used a Boxed iterator for the example simplicity.
@SvenMarnach fitted the types :
impl LimitCollection for ConcreteLimitCollection {
type Output<'a> = std::iter::Filter<std::slice::Iter<'a, Limit>, fn(&&Limit) -> bool>;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a> {
self.limits.iter().filter(|l| l.is_violated())
}
}