Паттерн, связывающий одну и ту же переменную с разными типами, разделяющими черту - PullRequest
0 голосов
/ 22 февраля 2020

У меня есть вопрос о сопоставлении с образцом для значений, разделяющих некоторое поведение через черту.

У меня есть enum с двумя вариантами, каждый из которых имеет значение привязки разных типов, где оба типа реализуют черту. Я пытаюсь выяснить, возможно ли создать один шаблон (в форме 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 => ...?

Ответы [ 2 ]

1 голос
/ 22 февраля 2020

Вы можете создать макрос, который разворачивается, чтобы соответствовать оператору.

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

}
0 голосов
/ 22 февраля 2020

Если все варианты реализуют эту черту, лучшее решение - реализовать черту для всего перечисления ( детская площадка ).

Соответствующий код:

impl T for E {
    fn f(&self) -> usize {
        match self {
            E::VarA(x) => x.f(),
            E::VarB(x) => x.f(),
        }
    }
}
...