Macros 将标识添加到多个重复会导致“重复”;局部歧义:多个解析选项“;
我正在尝试构建一个宏,该宏将使用函数调用列表(Macros 将标识添加到多个重复会导致“重复”;局部歧义:多个解析选项“;,macros,rust,Macros,Rust,我正在尝试构建一个宏,该宏将使用函数调用列表(test2())或标识符(test3)调用: 目前,它只支持函数调用: invoke!( ["str1", "str2"]: i32 => test1(), test2(); ["str3", "str1"]: i32 => test1(); ) 原始宏代码: macro_rules! invoke { ( $([$($field:expr),*]: $vtype:ty => $($func:iden
test2()
)或标识符(test3
)调用:
目前,它只支持函数调用:
invoke!(
["str1", "str2"]: i32 => test1(), test2();
["str3", "str1"]: i32 => test1();
)
原始宏代码:
macro_rules! invoke {
( $([$($field:expr),*]: $vtype:ty => $($func:ident$args:tt),*; )+ ) => {
$(
let x = vec![$($field),*];
let y = vec![$($func$args),*];
println!("{:#?}: {:#?}", x, y)
)+
};
}
当我尝试将其更改为支持两种形式时:
macro_rules! invoke {
( $([$($field:expr),*]: $vtype:ty => $($func:ident$args:tt),* $($newfunc:ident),*; )+ ) => {
$(
let x = vec![$($field),*];
let y = vec![$($func$args),*];
let z: Vec<$vtype> = vec![$newfunc()];
println!("{:#?}: {:#?} [{:#?}]", x, y, z)
)+
};
}
我知道可以通过:tt
构建此宏,但我找不到方法
此宏模式没有意义:
$($func:ident$args:tt),* $($newfunc:ident),*;
这表示要解析零个或多个标识符(func
),后跟零个或多个标识符(newfunc
)。如果输入是identfoo
,那么解析器将无法决定选择哪条语法路径,因为有一个有限的关于前瞻(大概是一个标记)
正如在评论中指出的,最简单的解决方案是引入新的语法来消除案例的歧义
macro_rules! invoke {
( $([$($field:expr),*]: $vtype:ty => $($func:ident$args:tt),* [$($newfunc:ident),*]; )+ ) => {{
$(
let x = vec![$($field),*];
let y = vec![$($func$args),*];
let z: Vec<$vtype> = vec![$($newfunc()),*];
println!("{:#?}: {:#?} [{:#?}]", x, y, z);
)+
}};
}
fn main() {
invoke!(
["str1", "str2"]: i32 => test1(), test2() [test3, test4];
["str3", "str1"]: i32 => test1() [test3];
);
}
fn test1() -> i32 { 42 }
fn test2() -> i32 { 42 }
fn test3() -> i32 { 42 }
fn test4() -> i32 { 42 }
这似乎对你的情况没有帮助,因为你希望先收集一堆a,然后收集一堆B。这将允许收集一堆a或B。在语法上,这类似于
(A | B)*#此表格
你想要什么
您能否更改调用的方式改为调用代码>吗?@kennytm它在代码中显式显示:invoke!([“str1”,“str2”]:i32=>test1()test2();[“str3”,“str1”]:i32=>test1();)
我在您的宏中发现错误,即使您说的宏正在工作。另外,你能展示一下你期望你的第一个例子会转化成什么吗?@PeterHall我不知道你怎么会出错。我添加了问题的链接,这是有效的代码示例。随着时间的推移,我添加了预期的样本。@mrLSD我的意思是,而不是invoke!([“str1”]:i32=>test1(),test2(),test3,test4)
,能否将语法更改为likeinvoke!([“str1”]:i32=>{test1()=>test3,test2()=>test4})
?感谢您的精彩回答。我是否理解,$args:tt
不可能设置为可选,即测试vs test()
?只要阅读此答案,它就应该更新。宏$($x:ident)?
现在有一个可选的修改器。
macro_rules! invoke {
( $([$($field:expr),*]: $vtype:ty => $($func:ident$args:tt),* [$($newfunc:ident),*]; )+ ) => {{
$(
let x = vec![$($field),*];
let y = vec![$($func$args),*];
let z: Vec<$vtype> = vec![$($newfunc()),*];
println!("{:#?}: {:#?} [{:#?}]", x, y, z);
)+
}};
}
fn main() {
invoke!(
["str1", "str2"]: i32 => test1(), test2() [test3, test4];
["str3", "str1"]: i32 => test1() [test3];
);
}
fn test1() -> i32 { 42 }
fn test2() -> i32 { 42 }
fn test3() -> i32 { 42 }
fn test4() -> i32 { 42 }
macro_rules! thing {
($name:ident$args:tt) => { println!("a") };
($name:ident) => { println!("b") };
}
fn main() {
thing!(foo); // b
thing!(foo()); // a
}