I'm trying to define a function that will take a reference as a parameter, and call a generic method on the referenced object, passing in a concrete value. I need a way of requiring that the generic type of the parameter passed to my function is a trait of the concrete type that the function will use it with. I can't seem to work out how to do this.
A minimal example of the sort of thing I'm trying to achieve:
trait Vehicle {}
trait Floating {}
struct Boat;
impl Vehicle for Boat {}
impl Floating for Boat {}
fn main() {
let mut a: Vec<Box<dyn Vehicle>> = vec![];
populate(&mut a); // Does not compile
let mut b: Vec<Box<dyn Floating>> = vec![];
populate(&mut b); // Also does not compile
}
fn populate(receiver: &mut Vec<Box<Boat>>) { // What should I put here?
receiver.push(Box::new(Boat{}));
}
Trying to compile this gives the following errors:
error[E0308]: mismatched types
--> src/main.rs:10:14
|
10 | populate(&mut a); // Does not compile
| ^^^^^^ expected struct `Boat`, found trait object `dyn Vehicle`
|
= note: expected mutable reference `&mut std::vec::Vec<std::boxed::Box<Boat>>`
found mutable reference `&mut std::vec::Vec<std::boxed::Box<dyn Vehicle>>`
error[E0308]: mismatched types
--> src/main.rs:13:14
|
13 | populate(&mut b); // Also does not compile
| ^^^^^^ expected struct `Boat`, found trait object `dyn Floating`
|
= note: expected mutable reference `&mut std::vec::Vec<std::boxed::Box<Boat>>`
found mutable reference `&mut std::vec::Vec<std::boxed::Box<dyn Floating>>`
I didn't expect this to compile, but I don't know how to change the signature of populate
so that it will. I come from Java land, where I would achieve this using this using a bounded wildcard (e.g. void populate(List<? super Boat> receiver)
), but I can't find anything to suggest that Rust offers equivalent semantics.
How might I go about fixing my definition of populate
here?
I'm new to Rust, so bear with me if I'm completely barking up the wrong tree. I've searched around, and can't seem to find an example of how this pattern should be implemented.
populate
to take aVec<Trait>
for any trait whichBoat
implements? – PimpernelVec<Box<Trait>>
, but essentially yes. I guess I would ideally expect it to also be able to take aVec<Box<Boat>>
as well. – AbrasionT
, and ask if it's a trait implemented byBoat
, so I don't think that as-is it is possible to write thepopulate
function. – Pimpernel