我正在尝试编写一个列出多个结构字段的宏,但有条件地仅从列表中的某些字段创建初始化程序代码。具体来说,可能看起来像这样:
#[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);
}
Foo
没有字段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,)*
}
}
};
}
现在,我知道对不同的重复使用不同的规则的技巧是将每个重复委托给辅助规则。这是相同的宏,将常规变体和不变体分开:
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
};
}
但这在这里没有帮助,因为我只委托$value
, not $field: $value,
。但我不能委托整个事情,因为从语法上讲,这不是宏可以生成/不能生成的一个标记树(?)。
有没有办法使用这个或另一个技巧来实现这一目标?如果可能的话,最好避免使用过程宏。