首页 > 解决方案 > 将相同变量绑定到共享特征的不同类型的模式

问题描述

我有一个关于通过特征共享某些行为的值的模式匹配的问题。

我有一个带有两个变体的枚举,每个绑定值都具有不同的类型,这两种类型都实现了一个特征。我试图弄清楚是否可以创建一个(E::VarA(x) | E::VarB(x)形式的)模式,其中我将两种类型绑定到一个常量,只要我只对使用共享行为感兴趣。

一个说明性示例:游乐场

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));
}

该代码显然无法编译,但它表明了我的意图。有没有办法让代码工作,最好比简单地拆分更pat1 | pat2 => ...优雅pat1 => ... ; pat2 => ...

标签: rustpattern-matchingtraits

解决方案


您可以制作一个展开以匹配语句的宏。

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()));

}

推荐阅读