我们说我有一个enum
,但有一些变种:
#[derive(Copy,Clone)]
enum Foo {
Left(isize),
Right(isize),
Other,
//...
}
我希望对此进行模式匹配,对Left
和Right
采用非常相似但不相同的处理。
我最终得到了:
match foo {
Left(i) | Right(i) => {
let i2 = match foo {
Left(_) => -i,
Right(_) => i,
_ => unreachable!(),
};
move_sideways(i2);
// non-trivial code, ie not a simple function call
},
Other => { ... }
}
这并不令人满意,并且依赖于第一次不消费foo
。我是否有一个很好的习惯用法,以避免重新匹配或复制规则?
答案 0 :(得分:2)
我可能会接受Lukas提出的建议,但无论如何我试图设计一些东西。如果您无法改变Foo
的构建方式,它可能对您有所帮助。
我不会说它超级优雅,但尝试了:
use self::Foo::*;
#[derive(Copy, Clone)]
enum Foo {
Left(isize),
Right(isize),
Other,
//...
}
impl From<Foo> for Option<isize> {
fn from(foo: Foo) -> Option<isize> {
match foo {
Left(i) => Some(-i),
Right(i) => Some(i),
_ => None
}
}
}
fn main() {
let foo = Left(4);
if let Some(i) = <Option<isize>>::from(foo) {
move_sideways(i);
} else {
match foo {
Other => { },
_ => unreachable!()
}
};
}
答案 1 :(得分:2)
无需修改数据结构就无法避免重复规则。但是如果你想避免让Foo
成为Copy
类型(保留所有其他类型),这里稍作修改:
let foo = Left(34);
match foo {
foo2 @ Left(_) | foo2 @ Right(_) => {
let i = match foo2 {
Left(i) => -i,
Right(i) => i,
_ => unreachable!(),
};
// ... non-trivial code
}
Other => (),
}
foo
中的值将移至foo2
。
(使用阴影可能看起来更干净 - foo
而不是foo2
...)
答案 2 :(得分:1)
首先想到的是将enum
包裹到Option
而不是使用Other
构造函数:
enum Foo {
Left(isize),
Right(isize)
}
let foo = Some(Left(1));
let x = match foo {
Some(y) => {
let i2 = match y {
Left(i) => -i,
Right(i) => i
};
do_something(i2)
},
None => 0
};
如果您不想这样做,可以链接两个match
- 表达式,并使用第一个来处理Left
和Right
的预处理:
let bar = Right(2);
let z = match match bar {
Left(i) => Some(-i),
Right(i) => Some(i),
Other => None
} {
Some(i) => do_something(i),
None => 0
};
如果由于您的案例更复杂,这无济于事,我只会使用一个match
- 表达式,其中包含Left
,Right
和Other
的单独案例并将公共代码移动到一个函数中。