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
)。如果输入是ident
foo
,那么解析器将无法决定选择哪条语法路径,因为有一个有限的关于前瞻(大概是一个标记)

正如在评论中指出的,最简单的解决方案是引入新的语法来消除案例的歧义

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)
,能否将语法更改为like
invoke!([“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
}