I am trying to implement a trait that works for Iterator and Iterator<&u32> seamlessly, and while I did manage to find a solution I am not sure that is the best one, or even a good one. I have included my first two non working solutions for reference.
Problem
Implement the following trait for iterators over u32
trait First {
fn first(self) -> Option<u32>;
}
Non working solutions
This first implementation :
impl<I> First for I
where I: Iterator<Item = u32> {
fn first(mut self) -> Option<u32> {
self.next()
}
}
will work for vec![1, 2, 3].into_iter().first() (Iterator) but not for vec![1, 2, 3].iter().first() which will yield the following error:
error[E0599]: the method `first` exists for struct `Iter<'_, {integer}>`, but its trait bounds were not satisfied
using this second implementation:
impl<'a, I> First for I
where I: Iterator<Item = &'a u32> {
fn first(mut self) -> Option<u32> {
Some(*self.next()?)
}
}
will fail this time on the into_iter() variant with the similar error:
error[E0599]: the method `first` exists for struct `IntoIter<{integer}>`, but its trait bounds were not satisfied
Note that in both cases the method is said to already exist, although the trait bounds are not satisfied. This means that it is note possible to use both definitions to have an overall working solution.
Working solution
This works:
impl<T, I> First for I
where
I: Iterator<Item = T>,
T: Borrow<u32>,
{
fn first(mut self) -> Option<u32> {
Some(*self.next()?.borrow())
}
}
while this works, I'm not sure how (what I understand of) the semantics of the Borrow trait would justify using it for that usage. Also I'm not sure how this is actually compiled in the end, but it seems a little pointless in the case of into_iter() to take a reference to and owned integer, only to deference and copy it.
Am I missing something to make this work, or is it a mistake to even try something like that (it's not much of an issue for Copy, but for Clone types, having a trait calling .clone() even when the type is already owned is a waste or resources)? And is there any way to make the error message more explicit: to explicitly state that the iterator is expecting an owned value an not a reference, rather than the message about unsatisfied traits?