Как сравнить перечисление без соответствия шаблону
Я хочу применить filter
на итераторе, и я придумал этот, и он работает, но он очень многословный:
.filter(|ref my_struct| match my_struct.my_enum { Unknown => false, _ => true })
Я бы скорее написал что-то вроде этого:
.filter(|ref my_struct| my_struct.my_enum != Unknown)
Это дает мне ошибку компиляции
binary operation `!=` cannot be applied to type `MyEnum`
Есть ли альтернатива сопоставлению подробных шаблонов? Я искал макрос, но не нашел подходящего.
Ответы
Ответ 1
Во-первых, вы можете использовать черту PartialEq
, например, #[derive]
:
#[derive(PartialEq)]
enum MyEnum { ... }
Тогда ваш "идеальный" вариант будет работать так, как есть. Однако для этого требуется, чтобы содержимое MyEnum
также реализовало PartialEq
, что не всегда возможно/требуется.
Во-вторых, вы можете реализовать макрос самостоятельно, что-то вроде этого (хотя этот макрос не поддерживает все виды шаблонов, например, альтернативы):
macro_rules! matches(
($e:expr, $p:pat) => (
match $e {
$p => true,
_ => false
}
)
)
Затем вы будете использовать его следующим образом:
.filter(|ref my_struct| !matches!(my_struct.my_enum, Unknown))
Существует RFC, чтобы добавить такой макрос в стандартную библиотеку, но он все еще обсуждается.
Ответ 2
Я бы использовал сопоставление с образцом, но я бы переместил его к методу на перечислении, чтобы закрытие фильтра было более аккуратным:
#[derive(Debug)]
enum Thing {
One(i32),
Two(String),
Unknown,
}
impl Thing {
fn is_unknown(&self) -> bool {
match *self {
Thing::Unknown => true,
_ => false,
}
}
}
fn main() {
let things = vec![Thing::One(42), Thing::Two("hello".into()), Thing::Unknown];
for t in things.iter().filter(|s| !s.is_unknown()) {
println!("{:?}", t);
}
}
См. также: