I have a trait and a thing that implements that trait:
trait HasPosition2D {
fn x(&self) -> &i32;
fn y(&self) -> &i32;
fn x_mut(&mut self) -> &mut i32;
fn y_mut(&mut self) -> &mut i32;
}
impl HasPosition2D for (i32,i32) {
fn x(&self) -> &i32 {&self.0}
fn y(&self) -> &i32 {&self.1}
fn x_mut(&mut self) -> &mut i32 {&mut self.0}
fn y_mut(&mut self) -> &mut i32 {&mut self.1}
}
I can now define generic functions that accept anything that implements HasPosition2D. e.g
fn print(p: &impl HasPosition2D) {
println!("{} {}", p.x(), p.y());
}
I have also defined a function that accepts anything that can be turned into an iterable of HasPosition2D. i.e
fn print_all(ps: impl IntoIterator<Item=impl HasPosition2D>) {
for p in ps {
println!("{} {}", p.x(), p.y());
}
}
This allows me to swap the container type without having to change the code. e.g
let ps = vec![(42,42), (42,42)];
print_all(ps);
let ps = [(42,42), (42,42)];
print_all(ps);
However, the above function moves the container, I would instead like to borrow. e.g
//does not complile
fn print_all2(ps: &impl IntoIterator<Item=impl HasPosition2D>) {
for p in ps {
println!("{} {}", p.x(), p.y());
}
}
But this gives the error:
error[E0277]: `&impl IntoIterator<Item = impl HasPosition2D>` is not an iterator
--> src\main.rs:35:14
|
35 | for p in ps {
| ^^ `&impl IntoIterator<Item = impl HasPosition2D>` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&impl IntoIterator<Item = impl HasPosition2D>`
= help: the trait `Iterator` is implemented for `&mut I`
= note: required because of the requirements on the impl of `IntoIterator` for `&impl IntoIterator<Item = impl HasPosition2D>`
I would also like to define a similar function that accepts a mutable borrow.
And finally, how could I create a type alias for each of these impl traits? ( using #![feature(type_alias_impl_trait)]
and/or #![feature(trait_alias)]
)
e.g, for the non borrowed version:
type HasPosition2DList = impl IntoIterator<Item=impl HasPosition2D>;
or
//does not compile
trait HasPosition2DList = IntoIterator<Item=impl HasPosition2D>;
How do I do this?
CodePudding user response:
into_iter
takes self
by value (not reference), so if you are wanting to avoid a move, then that won't fix your problem. Vec
can deref
into a slice, so I think you want something more like this, in order to accept either type as a paramter:
fn print_all(ps: &[impl HasPosition2D]) {
for p in ps {
println!("{} {}", p.x(), p.y());
}
}
You can then call it as you showed in your example, just adding &
to borrow:
fn main() {
let ps = vec![(42,42), (42,42)];
print_all(&ps);
let ps = [(42,42), (42,42)];
print_all(&ps);
}