There is no syntax for match
on types. The only way to do any kind of "downcasting" is via the Any
trait. You can use it with an impl MyTrait
if it also constrained to be 'static
:
use std::any::Any;
pub struct A;
pub struct B;
pub struct C;
pub trait MyTrait {}
impl MyTrait for A {}
impl MyTrait for B {}
impl MyTrait for C {}
fn do_something(mut element: impl MyTrait + 'static) {
let element = &mut element as &mut dyn Any;
if let Some(a) = element.downcast_mut::<A>() {
// do something with `a`
println!("is A");
} else if let Some(b) = element.downcast_mut::<B>() {
// do something with `b`
println!("is B");
} else {
// do something with `element`
println!("is unknown");
}
}
fn main() {
do_something(A);
do_something(B);
do_something(C);
}
is A
is B
is unknown
The two caveats with this code are 1) the 'static
constraint, meaning you can't use this with traits or implementations with non-static generic lifetimes; and 2) you can't get an owned version of A
or B
(the type of a
is &mut A
in the above code).
This type of code pattern is very un-idiomatic. If you want to have trait instances exhibit different behavior based on their implementations, you should have an associated method for it:
pub trait MyTrait {
fn do_something(self)
}
Or if you want to implement behavior on a closed-set of types with shared behavior, you should instead use an enum:
enum MyEnum {
A(A),
B(B),
}
fn do_something(element: MyEnum) {
match element {
MyEnum::A(a) => { println!("is A"); },
MyEnum::B(b) => { println!("is B"); },
}
}
With either of these methods, you don't have the same caveats of trying to circumvent the polymorphic trait system.
See also (none address the impl Trait
case, but they pretty much all say the same thing):