我有这样一个例子:
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)
}
_ => {
(...)
}
}
inner
是Bar
结构,但在Foo1
和Foo2
中不同:inner
用于Foo1
:Bar<I1>
inner
用于Foo2
:Bar<I2>
问题是,在上面的块中,
something
匹配Foo1
和Foo2
时的操作是完全相同的,但是重复两次相同的操作不是很优雅。我试过:
match something {
Foo::Foo1(inner) | Foo::Foo2(inner)=> {
inner.do(a_word)
_ => {
(...)
}
}
它不起作用,因为
inner
和Foo1
中的Foo2
是不同类型的(如前所述)那么我怎样才能把
Foo1
和Foo2
紧密地匹配起来呢?谢谢您!
最佳答案
我假设有时您希望对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/