Reputation: 1251
I'm trying to use generics for iterators in traits and am having a hard time understanding why it does not compile.
struct B {
values: Vec<(i64, i64)>,
}
pub trait IterableCustom {
fn get_iterator<'a, I>(&self) -> I
where
I: Iterator<Item = &'a (i64, i64)>;
}
impl IterableCustom for B {
fn get_iterator<'a, I>(&self) -> I
where
I: Iterator<Item = &'a (i64, i64)>,
{
let rev = self.values.iter().rev();
rev
}
}
It throws an error:
error[E0308]: mismatched types
--> src/lib.rs:17:9
|
12 | fn get_iterator<'a, I>(&self) -> I
| - - expected `I` because of return type
| |
| this type parameter
...
17 | rev
| ^^^ expected type parameter `I`, found struct `Rev`
|
= note: expected type parameter `I`
found struct `Rev<std::slice::Iter<'_, (i64, i64)>>`
For more information about this error, try `rustc --explain E0308`.
Upvotes: 1
Views: 198
Reputation: 1641
The only thing we know about I
is that I
implements Iterator<Item = &'a (i64, i64)>
, so I
can be any iterator type satisfying the trait bound.
Therefore, the type of rev
does not always equal to I
.
Without GAT or existential types (which are not in stable Rust yet), currently the best way to rewrite it is to return a boxed trait object.
struct B {
values: Vec<(i64, i64)>,
}
pub trait IterableCustom {
fn get_iterator(&self) -> Box<dyn Iterator<Item = &(i64, i64)> + '_>;
}
impl IterableCustom for B {
fn get_iterator(&self) -> Box<dyn Iterator<Item = &(i64, i64)> + '_> {
let rev = self.values.iter().rev();
Box::new(rev)
}
}
With generic associated types, the code can be rewritten as such.
#![feature(generic_associated_types)]
struct B {
values: Vec<(i64, i64)>,
}
pub trait IterableCustom {
type Iter<'a>: Iterator<Item = &'a (i64, i64)>
where
Self: 'a;
fn get_iterator<'a>(&'a self) -> Self::Iter<'a>;
}
impl IterableCustom for B {
type Iter<'a> = std::iter::Rev<std::slice::Iter<'a, (i64, i64)>>;
fn get_iterator<'a>(&'a self) -> Self::Iter<'a> {
self.values.iter().rev()
}
}
With existential types, the overly verbose std::iter::Rev<...>
type can be further reduced as such.
type Iter<'a> = impl Iterator<Item = &'a (i64, i64)>
where
Self: 'a;
Upvotes: 4