【问题标题】:Macro matching a single expr after [expr*], path[tt*] and ident[tt*] branches在 [expr*]、path[tt*] 和 ident[tt*] 分支之后匹配单个 expr 的宏
【发布时间】:2016-07-10 15:36:26
【问题描述】:

我正在尝试制作一个可以通过以下方式调用的宏:

mactest!(some::Path[1, 2, AnotherName[3, 4]])

相当于以下内容:

make_result(
    "some::Path", 
    1.convert(), 
    2.convert(), 
    make_result(
        "AnotherName", 
        3.convert(), 
        4.convert()
    )
)

其中convert 是一些将为一堆类型实现的特征。 (convertmake_result 具有相同的结果类型)。

这是我所到之处:

// Note: u32 is used as an example result type. 
// The real code attempts to create a more complicated object.

trait Foo {
    fn convert(&self) -> u32;
}

fn make_result(name: &str, data: Vec<u32>) -> u32 {
    // This example ignores name and makes a meaningless result
    data.iter().fold(0,|a, &b| a + b)
}


#[macro_export]
macro_rules! mactest {
    ( [ $($inner:expr),* ] ) => {{
        let mut result = Vec::new();
        $(
            // Process each element.
            result.push(mactest!($inner));
        )*
        result
    }};
    ($name:path [ $($inner:tt),* ] ) => {
        make_result(stringify!($name), mactest!([$($inner),*]))
    };
    ($name:ident [ $($inner:tt),* ] ) => {
        make_result(stringify!($name), mactest!([$($inner),*]))
    };
    // Process single value. This is never matched?
    ($x:expr) => {
        $x.convert()
    };
}

宏的第一个匹配分支应该将列表的每个元素与末尾的path/ident[items] 或单个项目.convert 分支匹配。但是最后一个分支永远不会到达,当单个项目进入宏时,锈会抱怨error: expected ident, found '1',即mactest!(1)

作为 rust 初学者,我的理由是宏有四种模式:[expr*]path[tt*]ident[tt*]expr。当我将类似 1 的内容传递给宏时,我不明白为什么上述任何模式都应该匹配/干扰。

有人可以解释为什么这不起作用吗?是否有解决方法来获得预期的结果?

【问题讨论】:

  • 您的宏在常规情况下不起作用:play.rust-lang.org/…。它抱怨“应为.] 或操作员之一,发现,

标签: macros rust


【解决方案1】:

通过从第一个开始并从那里向下尝试宏规则。所以如果你想防止你的其他规则在特殊情况下触发,你需要把特殊情况规则放在第一位。

Try it out in the playground

【讨论】:

  • 除此之外,问题在于外部调用匹配为:expr,这会阻止“特殊情况”规则永远匹配。这只能通过增量解析来完成。
  • 令我困惑的是,在mactest(1) 的情况下,我看不出前三个规则中的任何一个如何匹配1。这些是特殊情况,这就是为什么它们位于顶部。 1 不是 ident 也不是 path。为了缩小范围,this 错误消息真的让我感到困惑。 @DK。在这种情况下,增量解析是什么意思?
  • @porgarmingduod 我的就寝时间,但这(除其他外)在TLBoRM 中有解释。简短版本:macro_rules! 解析器真的愚蠢,而1 不是标识符这一事实问题。那个特定的公式是不可能开始工作的;请参阅第 2.3.1 节。
  • @DK。谢谢,这正是我需要的资源来弥补我关于 rust 宏的缺点。不敢相信当我在谷歌上搜索各种宏的东西时它从来没有出现过。
猜你喜欢
  • 1970-01-01
  • 2012-07-24
  • 1970-01-01
  • 2020-12-18
  • 1970-01-01
  • 2011-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多