impl T {
fn foobar(&self) {
match self {
T::A(inner) => bar(inner.foo()),
T::B(inner) => bar(inner.foo()),
}
}
}
I found these solutions:
For simple cases, enum_dispatch can work. But it has some limitations, e.g., not work with associate types, not IDE friendly. Another point is that it is required to use a trait for the inner types.
match_any and match_template seems powerful enough, but require user to provide all enum variants (as opposed to enum_dispatch).
I'm wondering is it possible (and reasonable) to auto generate an exhaustive pattern matching with arbitrary template code? Anyway, what's the best practice for such cases?
Thanks for your help. But these are not what I'm looking for. They are useful to convert an enum into one specific variant, but I'm looking for something like a (type unsafe) map on an enum with heterogeneous variants.
No, it's not possible. This is a gap in Rust's type system. Enum variants aren't types, and generics requires types, so you will have to use a match to bridge that gap every time.
In principle this could be solved without any additions to the type system per se. This could be valid code:
impl T {
fn foobar(&self) {
match self {
T::*(inner) => bar(inner.foo()),
}
}
}
where the * is expanded to all variants in the enum declaration. (Or even: all variants with matching field count/names.) This information is already present at this site for exhaustiveness checking.
Because macros are run before any types are known. That's because macros are capable of making code that defines or changes types, so Rust can't begin to figure out the types until all macros are finished generating code. Making macros type-aware would create a circular dependency in Rust's compilation model.
At the point when macro runs something like T is just the ASCII letter T, not an instance of a generic type. You can't even know if it's an enum (the enum_dispatch crate does hacky things to estimate that, and can't do it properly in all cases). Doing this properly may not even be possible, because fields of the enum may be generated by another macro, or in generic code thanks to type inference and recursion the exact types may depend on result of the function your macro is currently generating (so your macro's input depends on your macro's output).
If it's different than the existing same-type match self { T::A(inner) | T::B(inner) }, then the bar(inner) can't exist in the AST, because there is no way to express the superposition of the many types of inner.
That might be implemented as kind of a late-expansion macro that syntactically does copy'n'paste of the match arm for every variant. That could work, but it seems super narrow for one case.