编写一个 Rust 宏重复,它可能会也可能不会初始化结构体字段

Sil*_*eak 5 macros rust

我正在尝试编写一个列出多个结构字段的宏,但有条件地仅从列表中的某些字段创建初始化程序代码。具体来说,可能看起来像这样:

#[test]
fn test() {
    #[derive(PartialEq, Debug)]
    struct Foo {
        bar: usize,
    }

    let a = Foo {
        bar: 0,
    };

    let b = test!(Foo {
        bar: 0,
        #[nope] baz: 0,
    });

    assert_eq!(a, b);
}
Run Code Online (Sandbox Code Playgroud)

Foo没有 field baz,并且#[nope]应该告诉宏对该字段不执行任何操作;真正的宏会baz在一个位置使用,但不会在另一个位置使用,并且还需要处理其他“属性”。

这是接受调用但不忽略的基线宏baz

macro_rules! test {
    (
        $struct:ty {
            $($(#[$modifier:ident])? $field:ident: $value:expr,)*
        }
    ) => {
        {
            // don't mind this syntax workaround
            type X = $struct;
            X {
                $($field: $value,)*
            }
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

现在,我知道对不同的重复使用不同的规则的技巧是将每个重复委托给辅助规则。这是相同的宏,将常规变体和不变体分开:

macro_rules! test {
    (
        $struct:ty {
            $($(#[$modifier:ident])? $field:ident: $value:expr,)*
        }
    ) => {
        {
            type X = $struct;
            X {
                $($field: test!(@field $(#[$modifier])? $field: $value),)*
            }
        }
    };

    (
        @field $field:ident: $value:expr
    ) => {
        $value
    };

    (
        @field #[nope] $field:ident: $value:expr
    ) => {
        $value
    };
}
Run Code Online (Sandbox Code Playgroud)

但这在这里没有帮助,因为我只委托$value,而不是$field: $value,。但我不能委托整个事情,因为从语法上讲,这不是宏可以生成/不能生成的一个标记树(?)。

有没有办法使用这个或另一个技巧来实现这一目标?如果可能的话,最好避免使用过程宏。