I am trying to write a conversion trait that can take both Iterators to references and Iterators to mutable references.
Sadly, it seems that once you implement a trait for Iter<&>
, you cannot implement the trait also for Iter<&mut>
as they seem to collide. Which doesn't make sense, though, because Iter<&mut>
doesn't seem to be able to utilize the implementation for Iter<&>
.
Here is a minimal example:
// A dummy object
#[derive(Debug)]
struct MyObj(i32);
// A collection of MyObj references
#[derive(Debug)]
struct RefVec<'a>(Vec<&'a MyObj>);
// Goal: create a conversion function that can take *either* a `Iterator<&MyObj>` *or* `Iterator<&mut MyObj>`.
// Attempt: Create a Conversion Trait and implement it for both of those types
trait ConvertToRefVec<'a> {
fn convert(&mut self) -> RefVec<'a>;
}
// Implement the conversion for Iter<&MyObj>
impl<'a, T> ConvertToRefVec<'a> for T
where
T: Iterator<Item = &'a MyObj>,
{
fn convert(&mut self) -> RefVec<'a> {
RefVec(self.collect::<Vec<_>>())
}
}
// Problem: the impl above does not apply to Iter<&mut MyObj>. But the attempt to write an impl
// for Iter<&mut MyObj> fails with the message that it collides with the impl above:
impl<'a, T> ConvertToRefVec<'a> for T
where
T: Iterator<Item = &'a mut MyObj>,
{
fn convert(&mut self) -> RefVec<'a> {
RefVec(self.collect::<Vec<_>>())
}
}
fn main() {
let owned = [MyObj(42), MyObj(69)];
let ref_vec = owned.iter().convert();
println!("{:?}", ref_vec);
let ref_vec = owned.iter_mut().convert();
println!("{:?}", ref_vec);
}
Which gives me:
error[E0119]: conflicting implementations of trait `ConvertToRefVec<'_>`
--> src/main.rs:27:1
|
16 | / impl<'a, T> ConvertToRefVec<'a> for T
17 | | where
18 | | T: Iterator<Item = &'a MyObj>,
19 | | {
... |
22 | | }
23 | | }
| |_- first implementation here
...
27 | / impl<'a, T> ConvertToRefVec<'a> for T
28 | | where
29 | | T: Iterator<Item = &'a mut MyObj>,
30 | | {
... |
33 | | }
34 | | }
| |_^ conflicting implementation
But if I leave out the impl
for Iterator<&mut>
, then I get this error:
error[E0599]: the method `convert` exists for struct `std::slice::IterMut<'_, MyObj>`, but its trait bounds were not satisfied
--> src/main.rs:42:36
|
42 | let ref_vec = owned.iter_mut().convert();
| ^^^^^^^ method cannot be called on `std::slice::IterMut<'_, MyObj>` due to unsatisfied trait bounds
|
::: /home/.../.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/iter.rs:187:1
|
187 | pub struct IterMut<'a, T: 'a> {
| -----------------------------
| |
| doesn't satisfy `<_ as Iterator>::Item = &MyObj`
| doesn't satisfy `std::slice::IterMut<'_, MyObj>: ConvertToRefVec`
|
note: trait bound `<std::slice::IterMut<'_, MyObj> as Iterator>::Item = &MyObj` was not satisfied
--> src/main.rs:18:17
|
16 | impl<'a, T> ConvertToRefVec<'a> for T
| ------------------- -
17 | where
18 | T: Iterator<Item = &'a MyObj>,
| ^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
So my question is: How can I write such a conversion mechanism that works with both Iterator<Item = &MyObj>
and Iterator<Item = &mut MyObj
?