问题
I have a question about pattern matching on values sharing some behaviour through a trait.
I have an enum with two variants, each binding value of different types, where both types implement a trait. I'm trying to figure out whether it's possible to create a single pattern (of the E::VarA(x) | E::VarB(x)
form) in which I bind both types to a single constant, provided I'm only interested in using the shared behaviour.
An illustrative example: Playground:
trait T {
fn f(&self) -> usize;
}
struct A;
impl T for A {
fn f(&self) -> usize { 1 }
}
struct B;
impl T for B {
fn f(&self) -> usize { 2 }
}
enum E {
VarA(A),
VarB(B),
}
fn unwrap(e: E) -> usize {
match e {
E::VarA(v) | E::VarB(v) => T::f(&v)
}
}
fn main() {
let val = E::VarA(A{});
println!("{}", unwrap(val));
}
The code obviously does not compile, but it shows my intentions. Is there a way to make the code work, preferably more elegant than simply splitting the pat1 | pat2 => ...
into pat1 => ... ; pat2 => ...
?
回答1:
You can make a macro that unwraps to match statement.
trait T {
fn f(&self) -> usize;
}
struct A;
impl T for A {
fn f(&self) -> usize { 1 }
}
struct B;
impl T for B {
fn f(&self) -> usize { 2 }
}
enum E {
VarA(A),
VarB(B),
}
macro_rules! unwrap {
($value:expr, $pattern:pat => $result:expr) => {
match $value {
E::VarA($pattern) => $result,
E::VarB($pattern) => $result,
}
};
}
fn main() {
let a = E::VarA(A{});
let b = E::VarB(B{});
println!("a:{} b:{}",
unwrap!(a, ref sm => sm.f()),
unwrap!(b, ref sm => sm.f()));
}
回答2:
If all variants implement this trait, the best solution is to implement the trait for the whole enum (playground).
Relevant code:
impl T for E {
fn f(&self) -> usize {
match self {
E::VarA(x) => x.f(),
E::VarB(x) => x.f(),
}
}
}
来源:https://stackoverflow.com/questions/60346796/pattern-binding-the-same-variable-to-different-types-sharing-a-trait