I have an enum, all variants of which implement the same trait. Is there a way to access the trait methods without matching all the variants?
trait Trait {
fn method(&self) -> bool {
true
}
}
struct Foo;
impl Trait for Foo {}
struct Bar;
impl Trait for Bar {}
enum Enum {
Foo(Foo),
Bar(Bar),
}
fn main() {
let variant = Enum::Foo(Foo {});
// is it possible to do the same without matching all the possible variants
// knowing that all the variants implement the trait?
match variant {
Enum::Foo(x) => x.method(),
Enum::Bar(x) => x.method(),
};
}
I've chosen this structure as all the information about a step lives in one place. But if I implement the trait for the enum - a part of logic would move there. Proxying a few trait method in the enum implementation, while verbose, still feels better, as it mindless. If I add a new step and forget to write the proxy method, compiler will remind me, as there's an exhaustive match there. Also the verbosity can probably be mitigated by a macro.
Why would it? You don't have to inline nor duplicate all of the interesting logic, and you shouldn't: just forward it directly to the associated values of each variant!
Yep, that what I mean by proxying, but instead of implementing the trait, I just added those methods directly into the enum implementation. Maybe I got @RustyYato 's advice wrong, but I thought they suggested to move trait implementation from inner structures to the enum. So inner structures won't have the trait implemented and I'd use enum variants instead of them.
The typical approach is as @H2CO3 indicated, and what I believe @RustyYato actually meant, you just implement the trait on your enum and dispatch (proxy) to the variants within, a sort of boiler-plate form of dynamic dispatch. Both the enum and the types wrapped in variants have the trait implemented.
Matching in this case isn't optional. The reason is that before matching, you don't know which variant you're dealing with, and matching allows for solving that problem.
The knowledge about the variant wouldn't be necessary if compiler knew that all the variants implement this trait. But I guess there's no way to let it know for now.
The only place that I can see for bugs in a match expression is in the guards, if there are any. And there wouldn't be any here.
The fact that the enum is exhaustive ensures that the match must be exhaustive as well. This means that if you change any of the variants, or add or remove a variant, you'll get compile errors at the places where you use match on the variants of that enum.
This is in stark contrast to e.g. switch-case in almost all other mainstream languages: changing the enum in those PLs wouldn't result in a compile error at all.
All in all, not really a lot of space for bugs to creep in when dealing with exhaustive enums.
I ended up splitting static members into utility function and using enum_dispatch. It also provides From<InnerStruct> implementations for all the variants.