web-dev-qa-db-ja.com

パターンマッチングなしで列挙型を比較す​​る方法

イテレータに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`

詳細なパターンマッチングの代替手段はありますか?マクロを探しましたが、適切なマクロが見つかりませんでした。

28
Christoph

まず、PartialEq traitを使用できます。たとえば、#[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 がありますが、まだ検討中です。

42

パターンマッチングを使用しますが、enumのメソッドに移動して、フィルタークロージャーがよりきれいになるようにします。

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

こちらもご覧ください:

3
Shepmaster