I'm still fairly new to rust. I would like to use a variable to choose between one of several functions which return structs of different types, but all of which have the same trait implemented. I would then like to pass the returned struct from the selected function to some functions which are meant to accept any variable which has that trait. However, I can't figure out how to do it. I've read How do I overcome match arms with incompatible types for structs implementing same trait? but I'm missing something because I still can't get it to work. The function which I pass the returned value to doesn't accept the value - see below.
Here's a simplified example using one of the methods from the above link:
trait IsEven {
fn is_even(&self) -> bool;
}
struct First {
v: u8,
}
impl IsEven for First {
fn is_even(&self) -> bool {
self.v % 2 == 0
}
}
struct Second {
v: Vec<u8>,
}
impl IsEven for Second {
fn is_even(&self) -> bool {
self.v[0] % 2 == 0
}
}
fn make1() -> First {
First{v: 5}
}
fn make2() -> Second {
Second{v: vec![2, 3, 5]}
}
fn requires_is_even(v: impl IsEven) {
println!("{:?}", v.is_even());
}
fn main() {
for i in 0..2 {
let v1;
let v2;
let v = match i {
0 => {
v1 = make1();
&v1 as &IsEven
}
_ => {
v2 = make2();
&v2 as &IsEven
}
};
requires_is_even(v); // This is where it fails
}
}
The error I get in this case is:
52 | requires_is_even(v);
| ^^^^^^^^^^^^^^^^ the trait `IsEven` is not implemented for `&dyn IsEven`
I've also tried using Box as in some of the other examples in the link above, but still can't get it to work. Can anyone help?
Thanks
Bob
requires_is_even
, as you've written it, receives an object that implementsIsEven
by value, although all methods on the trait takeself
by shared reference. However, despite that,&dyn IsEven
doesn't automatically implementIsEven
(though we can add that implementation ourselves, see below).You have a few options here:
Change the function to receive an object implementing
IsEven
by shared reference. (This version does static dispatch.)Note: The
?Sized
bound is necessary here becauseimpl Trait
in argument position is syntactic sugar for a type parameter, and type parameters have an implicitSized
bound.Change the function to receive an
IsEven
trait object by shared reference. (This version does dynamic dispatch.)Implement
IsEven
for any shared reference to a type that implementsIsEven
.Note: By adding the
?Sized
bound, thisimpl
applies to&dyn IsEven
as well. Trait objects (dyn IsEven
here, not&dyn IsEven
orBox<dyn IsEven>
) automatically implement their corresponding trait (if the trait is object-safe, otherwise the trait object type isn't usable at all, by definition).