简体   繁体   English

在宏中匹配类似元组的枚举变体,其中枚举类型和变体是元变量:如何编写匹配模式?

[英]Matching tuple-like enum variants in a macro, where enum type and variants are metavariables: how do I write the matching pattern?

Concisely put into Rust code, I'm trying to generate a pattern match like this:简而言之,放入 Rust 代码中,我正在尝试生成这样的模式匹配:

if let Foo::Variant(_) = value {}
//     ^^^^^^^^^^^^^^^

in a macro, with both Foo (a type) and Variant (an identifier) passed to the macro as metavariables.在宏中, Foo (类型)和Variant (标识符)都作为元Variant传递给宏。 In the real use case, I'm generating a match instead of an if let and am using multiple variants of the same enum, but if let resulted in a shorter reproducible example.在实际用例中,我生成了一个match而不是if let并且我使用了同一枚举的多个变体,但是if let导致了一个更短的可重现示例。

This works with simple enums:这适用于简单的枚举:

enum Foo {
    Variant,
}

macro_rules! match_enum {
    (
        $value:ident: <$enum:ty>::$variant:ident
    ) => {
        if let <$enum>::$variant = $value {}
    };
}

fn main() {
    let foo = Foo::Variant;
    match_enum!(foo: <Foo>::Variant);
}

This compiles.这编译。

However, when I make the enum variant tuple-like, it breaks (changes highlighted):但是,当我使 enum 变体元组类似时,它会中断(突出显示的更改):

enum Foo {
    Variant(usize),
//         ^^^^^^^
}

macro_rules! match_enum {
    (
        $value:ident: <$enum:ty>::$variant:ident
    ) => {
        if let <$enum>::$variant(_) = $value {}
//                              ^^^
    };
}

fn main() {
    let foo = Foo::Variant(0);
//                        ^^^
    match_enum!(foo: <Foo>::Variant);
}
   |         if let <$enum>::$variant(_) = $value {}
   |                -----------------^^^ unexpected `(` after qualified path
   |                |
   |                the qualified path
...
   |     match_enum!(foo: <Foo>::Variant);
   |     --------------------------------- in this macro invocation

I have tried some variations, more or less blindly;我或多或少盲目地尝试了一些变体; $enum::$variant(_) , <$enum::$variant>(_) , <$enum::$variant>::(_) among them. $enum::$variant(_) , <$enum::$variant>(_) , <$enum::$variant>::(_)其中。

Is this possible?这可能吗? Am I perhaps using the wrong types of metavariables?我可能使用了错误类型的元变量吗?

This question seems to be related, but it focuses on mixing unit and tuple variants, and has not been resolved. 这个问题似乎是相关的,但它侧重于混合单元和元组变体,尚未解决。

The problem seems to be caused by the $enum metavariable, as the following slight modifications show:问题似乎是由$enum变量引起的,如下所示:

macro_rules! match_enum {
    (
        $value:ident: <$enum:ty>::$variant:ident
    ) => {
        // does not fix the problem
        if let <$enum>::Variant(_) = $value {}
        // fixes the problem
        if let Bar::$variant(_) = $value {}
    };
}

As the problem happens on the syntax level, we can try change the syntactic makeup of the generated code, in particular by introducing a type alias.由于问题发生在语法级别,我们可以尝试更改生成代码的语法构成,特别是通过引入类型别名。 We then need to scope that type to not leak out of the macro:然后,我们需要确定该类型的范围,以免从宏中泄漏:

macro_rules! match_enum {
    (
        $value:ident: <$enum:ty>::$variant:ident
    ) => {
        {
            type Enum = $enum;
            if let Enum::Variant(_) = $value {}
        }
    };
}

It's just a workaround, but it's clean enough.这只是一种解决方法,但它足够干净。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM