web-dev-qa-db-fra.com

Comment comparer l'énumération sans correspondance de modèle

Je veux appliquer filter sur un itérateur et je suis venu avec celui-ci et cela fonctionne, mais il est super verbeux:

.filter(|ref my_struct| match my_struct.my_enum { Unknown => false, _ => true })

Je préfère écrire quelque chose comme ceci:

.filter(|ref my_struct| my_struct.my_enum != Unknown)

Cela me donne une erreur de compilation

binary operation `!=` cannot be applied to type `MyEnum`

Existe-t-il une alternative à la correspondance de motifs verbeux? J'ai cherché une macro mais je n'ai pas trouvé de macro appropriée.

36
Christoph

Tout d'abord, vous pouvez utiliser le trait PartialEq, par exemple, par #[derive]:

#[derive(PartialEq)]
enum MyEnum { ... }

Ensuite, votre variante "idéale" fonctionnera telle quelle. Cependant, cela nécessite que le contenu de MyEnum implémente également PartialEq, ce qui n'est pas toujours possible/souhaité.

Deuxièmement, vous pouvez implémenter une macro vous-même, quelque chose comme ça (bien que cette macro ne prenne pas en charge toutes sortes de modèles, par exemple, des alternatives):

macro_rules! matches(
    ($e:expr, $p:pat) => (
        match $e {
            $p => true,
            _ => false
        }
    )
)

Ensuite, vous l'utiliseriez comme ceci:

.filter(|ref my_struct| !matches!(my_struct.my_enum, Unknown))

Il y a n RFC pour ajouter une telle macro dans la bibliothèque standard, mais elle est toujours en discussion.

54
Vladimir Matveev

J'utiliserais la correspondance de motifs, mais je la déplacerais vers une méthode sur l'énumération afin que la fermeture du filtre soit plus ordonnée:

#[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);
    }
}

Voir également:

5
Shepmaster

Vous pouvez utiliser if let Some(x) = option { then } idiome avec le même if let construire mais sans déstructurer:

if let Unknown = my_struct.my_enum { false } else { true }
0
Miha_x64