这样可行,但test_macro
只接受一个参数:
macro_rules! test_define (
($name:ident) => (
macro_rules! $name (
( $x:expr ) => (
// something
)
);
)
);
test_define!(test_macro);
如果我尝试这样做:
macro_rules! test_define2 (
($name:ident) => (
macro_rules! $name (
( $($x:expr),* ) => (
// something
)
);
)
);
test_define2!(test_macro2);
编译失败:
error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
--> src/main.rs:4:16
|
4 | ( $($x:expr),* ) => (
| ^^^^^^^^^
答案 0 :(得分:5)
nested macros don't allow repetitions in binding patterns (issue #35853)已知错误。
不幸的是,没有解决方法。唯一的解决方案是将API更改为不依赖于嵌套宏中的重复。
答案 1 :(得分:3)
虽然无法直接执行此操作({3}},但您可以使用kennytm described in this answer执行此操作(如果您确实需要,否则我不会推荐 >)。
虽然使用procedural macros时可能要简单得多,但stable
也可以这样做。
如果我错过任何事情或者将来使用nightly
这样的话可能会出现问题,请告诉我。
所以,让我们只复制custom derive中的示例,然后查看代码的这一部分:
fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens {
let name = &ast.ident;
quote! {
impl HelloWorld for #name {
fn hello_world() {
println!("Hello, World! My name is {}", stringify!(#name));
}
}
}
}
在quote!
宏内部,您不仅限于struct
的实施。你可以改成这个
quote! {
macro_rules! #name {
($($expr:expr),*) => {
// something
}
}
}
现在你有一个与struct
具有相同名称的宏,它带有无限量的参数。
要在另一个宏中执行此操作,外部宏只需看起来像这样:
macro_rules! test_define {
($name:ident) => {
#[allow(non_camel_case_types)] // because macro names are lower case
#[allow(dead_code)] // because this struct should never be used
#[derive(HelloWorld)]
struct $name { }
}
};
现在你可以调用test_define
然后调用内部宏:
test_define!(foo);
fn main() {
foo!()
}
但是,仍有一个问题:人们可能会意外访问您的结构。所以有办法规避这个问题(每个解决方案都是将问题与相同数字直接联系起来):
以一种防止意外访问的方式命名结构:
macro_rules! test_define {
($name:ident) => {
#[allow(dead_code)]
#[derive(HelloWorld)]
struct Dgfggsdfgujksdsdsdfsdfsdg {
$name: u8,
}
}
};
您必须在struct field
内更改here以使用name
代替quote!
,以防test_define!
被调用多次test_define!
你有2个具有相同名称的结构,导致编译时错误。
为防止两个相同的结构名称,您还可以更改macro_rules! test_define {
($name:ident, $rep_guard:ident) => {
#[allow(non_camel_case_types)]
#[allow(dead_code]
#[derive(HelloWorld)]
struct $rep_guard {
$name: u8,
}
}
};
以获取其他参数:
struct field
您使用name
代替test_define!(foo,fvgfdgdfgdfgd)
此方法。现在使用你必须写struct
,这真的很尴尬,所以我不推荐这个。
这可能是最好的选择,现在您可以保留解决方案1 中的奇怪module
名称,并将整个内容放在test_define!
中。这意味着没有人可以意外地访问创建的结构,并且您可以对macro_rules! test_define {
($name:ident) => {
#[macro_use] // to use the macro in the current module
mod $name {
#[allow(dead_code)]
#[derive(HelloWorld)]
struct Dgfggsdfgujksdsdsdfsdfsdg {
$name: u8,
}
}
}
};
进行无限量的调用。
dead_code
编译器应该只删除所有这些结构,因为它们是--release
(至少在使用quote!
标志构建时)。如果需要,您可以通过添加#[macro_export]
来调整String
。
另一个优点是proc宏使用您的源代码的方式与Tokens
或String
相同,可以转换为test_derive!(foo)
,这意味着您可以创建多个宏,例如:
foo!()
=> foo_with_var!(75)
,HapiContext context = new DefaultHapiContext(modelClassFactory)
PipeParser pipeParser = context.getPipeParser();
pipeParser.setValidationContext(new NoValidation());
pipeParser.getParserConfiguration().setAllowUnknownVersions(true);
Message msg = pipeParser.parse(document);
Parser xmlParser = context.getXMLParser();
return xmlParser.encode(msg);
如果你有什么不明白的地方,请问。