I'm trying to generalize .split
from slices to iterators, and I can't seem to get the types right. This is partially because I'm not very experienced with Rust, and partially because the error message is weirdly vague for what I've seen from Rust. I've included what I believe are the relevant snippets, but there's also a trait Splittable
and an implementation for it. The errors (I believe the second error is caused by the first, please tell me if that's not correct):
struct Split<I: Iterator, P: Fn(&I::Item) -> bool> {
iter: I,
pred: P,
}
impl<I: Iterator, P: Fn(&I::Item) -> bool> Iterator for Split<I, P> {
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.cloned()
.position(|x| (self.pred)(&x))
.map(|i| self.iter.take(i))
}
}
error[E0271]: type mismatch resolving `<I as std::iter::Iterator>::Item == &_`
--> src/main.rs:13:14
|
13 | .cloned()
| ^^^^^^ expected associated type, found reference
|
= note: expected associated type `<I as std::iter::Iterator>::Item`
found reference `&_`
= note: consider constraining the associated type `<I as std::iter::Iterator>::Item` to `&_` or calling a method that returns `<I as std::iter::Iterator>::Item`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0599]: no method named `position` found for struct `std::iter::Cloned<I>` in the current scope
--> src/main.rs:14:14
|
14 | .position(|x| (self.pred)(&x))
| ^^^^^^^^ method not found in `std::iter::Cloned<I>`
|
= note: the method `position` exists but the following trait bounds were not satisfied:
`<I as std::iter::Iterator>::Item = &_`
which is required by `std::iter::Cloned<I>: std::iter::Iterator`
The particular error message you are getting is a little misleading. What it is really complaining about is that std::slice::cloned
requires an iterator over references, which you can see from its definition:
fn cloned<'a, T>(self) -> Cloned<Self>
where
Self: Iterator<Item = &'a T>,
T: 'a + Clone,
It requires an iterator over references to items that implement Clone
(and the description states that it is useful for converting iterators over &T to iterators over T).
I suspect, however, that you are not trying to clone the items that are being iterated, rather that you are trying to clone the iterator itself. For that you would use the clone
method, rather than cloned
, and you would have to add a bound to ensure that the iterator is clonable, like this:
struct Split<I, P>
where
I: Iterator + Clone,
P: Fn(&I::Item) -> bool
There are a few other problems in your code:
self
multiple times, to access the iter
and pred
.self.iter
into the closure inside map
take
consumes the iterator you call it on, so even if you refactor to avoid the above two problems, it still will not compile.If you did intend to restrict your implementation to iterators over references, you could define your bounds like this:
struct Split<'a, I, T, P>
where
I: Iterator<Item=&'a T>,
T: 'a + Clone,
P: Fn(&I::Item) -> bool
Then you would be able to use cloned
.