rust - 将具有相同泛型的相同结构的枚举匹配

标签 rust rust-cargo

我有这样一个例子:

pub enum Foo {
    Foo1(Foo1),
    Foo2(Foo2),
    Foo3(Foo3),
}

在哪儿
pub type Foo1 = Bar<I1>;
pub type Foo2 = Bar<I2>;

在哪儿
struct Bar<I>{
   var: I,
   ...
}

impl Bar{
   fn do(word: &str){
      ...
   }
}

在这里,我正在编写另一个需要match块的函数:
match something {
   Foo::Foo1(inner) => {
       inner.do(a_word)
   }
   Foo::Foo2(inner) => {
       inner.do(a_word)
   }
   _ => {
       (...)
   }
}

innerBar结构,但在Foo1Foo2中不同:
inner用于Foo1Bar<I1>
inner用于Foo2Bar<I2>
问题是,在上面的块中,something匹配Foo1Foo2时的操作是完全相同的,但是重复两次相同的操作不是很优雅。
我试过:
match something {
   Foo::Foo1(inner) | Foo::Foo2(inner)=> {
       inner.do(a_word)
   _ => {
       (...)
   }
}

它不起作用,因为innerFoo1中的Foo2是不同类型的(如前所述)
那么我怎样才能把Foo1Foo2紧密地匹配起来呢?
谢谢您!

最佳答案

我假设有时您希望对Foo项运行相同的操作,而不考虑变量,而有时您希望根据变量更改逻辑。对于第二种情况,我不认为有任何方法可以绕过匹配块,或者,如果您只关心一个变量,则可以使用类似的方法:

if let Foo::Foo1(inner) = &foo {
    &inner.do_something(a_word);
}

(我更改了您的函数名,以避免保留关键字“do”。)
对于第一种情况,不管Foo枚举的变量是什么,您经常要执行相同的操作,您能在Foo中创建一些helper函数吗?例如,这将获得对所有变体的内部Bar<I>的引用:
fn get_inner(&self) -> &Bar<I> {
    match self {
        Foo::Foo1(inner) | Foo::Foo2(inner) | Foo::Foo3(inner) => inner,
    }
}

你可以这样称呼它:
foo.get_inner().do_something(a_word);

只有当Foo的每个变体都有一个Bar时,这才有效。否则,可以将get_inner()的返回类型更改为Option<&Bar<I>>
如果有几个不同的函数需要调用,可以创建一些帮助函数,使您可以调用函数,而不必考虑Foo的变体,例如:
fn run(&self, value: &str, f: &Fn(&Bar<I>, &str) -> ()) {
    f(self.get_inner(), value);
}

本例中的签名是f是Bar<I>上的一个方法,它引用一个字符串片段。可以这样称呼:
foo.run(a_word, &Bar::do_something);

但要调用的特定函数可以在运行时计算出来,只要它与签名匹配。如果只有Foo的一些变体有一个内部条,那么可以将run()更改为仅在有条可以调用函数时才调用该函数。
下面是完整的代码示例,我对您要做的事情做了很多假设:
#![allow(dead_code)]

fn main() {
    match_enum();
}

pub type Foo1<I1> = Bar<I1>;
pub type Foo2<I2> = Bar<I2>;
pub type Foo3<I3> = Bar<I3>;

pub struct Bar<I> {
    var: I,
}

impl<I> Bar<I> {
    fn do_something(&self, word: &str) {
        println!("\nBar.do_something(): {}", word);
    }
}

pub enum Foo<I> {
    Foo1(Foo1<I>),
    Foo2(Foo2<I>),
    Foo3(Foo3<I>),
}

impl<I> Foo<I> {
    fn get_inner(&self) -> &Bar<I> {
        match self {
            Foo::Foo1(inner) | Foo::Foo2(inner) | Foo::Foo3(inner) => inner,
        }
    }

    fn run(&self, value: &str, f: &Fn(&Bar<I>, &str) -> ()) {
        f(self.get_inner(), value);
    }
}

fn match_enum() {
    let a_word = "abc";
    let foo = Foo::Foo1(Bar { var: "foo1_bar" });

    // Call a function only for certain variants of Foo:
    match &foo {
        Foo::Foo1(inner) => {
            &inner.do_something(a_word);
        }
        Foo::Foo2(inner) => {
            &inner.do_something(a_word);
        }
        _ => {}
    }

    // Call a function only for one variant of Foo:
    if let Foo::Foo1(inner) = &foo {
        &inner.do_something(a_word);
    }

    // Call a function regardless of the variant of Foo:
    foo.get_inner().do_something(a_word);

    // As above but using a function that could have been chosen
    // at runtime:
    foo.run(a_word, &Bar::do_something);

}

埃塔:我想我漏掉了一些东西,因为我上面写的方式很好:
match &foo {
    Foo::Foo1(inner) | Foo::Foo2(inner) => {
        &inner.do_something(a_word);
    }
    _ => {}
}

但是在您的文章中,您说等效的代码不起作用,这意味着inner在Foo1和Foo2中都不是同一类型。所以我一定是用和你的代码不匹配的方式设置的。你能把Foo,Foo1,Foo2,Foo3和Bar的完整定义贴出来吗?
在您发布的示例中,您没有对Bar.var执行任何操作。问题是您需要对不同类型的Bar.var执行操作,而不是需要区分Foo1、Foo2和Foo3?

关于rust - 将具有相同泛型的相同结构的枚举匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57480977/

相关文章:

rust - 无法在数组中的 `&` 引用中可变地借用数据

module - 我可以将对象公开用于集成测试和/或基准测试吗?

rust - 我如何导致编译在 CI 警告时失败并在 .cargo/config 中设置额外的 rustflags?

rust - 为什么元组结构和枚举变体的行为类似于函数

rust - 实现一个复杂的自定义结构序列化器

rust - 有什么比在原始套接字上使用 libc 来实现任意协议(protocol)更好的呢?

rust - 相同代码 : spurious compile time errors? 的 cargo 构建

python - 安装 web3 时出错 [tester] : Failed building wheel for blake2b-py

testing - 如何递归测试目录下的所有 crate ?

Rust 生命周期,数据流入其他引用