声明性宏 - 括号中的表达式后面可以跟任意匹配器。为什么?

Declarative macros - bracketed expressions can be followed by arbitrary matchers. Why?

我正在试验声明性宏,我考虑过使用它们重新创建 F# 序列表达式。 第一次尝试触发了编译错误:

macro_rules! genexp {
  (for $item:ident in $range:expr -> $expr:expr) => {
    $range.map(|$item| $expr)
  }
}

`$range:expr` is followed by `->`, which is not allowed for `expr` fragments
allowed there are: `=>`, `,` or `;`rustc

但是,以下代码可以编译并正常工作:

macro_rules! genexp {
  (for $item:ident in [$range:expr] -> $expr:expr) => {
    $range.map(|$item| $expr)
  }
}

fn main() {
    let foo = genexp!(for x in [0..20] -> x * x);
    println!("{:?}", foo.collect::<Vec<_>>())
}

//OUTPUT: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]

我的问题是,为什么? Rust 参考中的 Macros By Example 部分指出:

  • expr and stmt may only be followed by one of: =>, ,, or ;.

我没有看到关于各种括号或其他分隔符的特殊处理的信息。

$range:expr ->

Rust 语言将来可以扩展,其中 -> 成为表达式的有效部分。这个想法是宏明确地 future-compatible 随着对 Rust 的更新,所以这是不允许保守的。

[$range:expr] ->

Rust 语言永远不会扩展涉及不平衡的特性 brackets/parents/braces [](){}。因此,当 Rust 解析器看到 [ 时,它可以立即扫描匹配的 ]。因此,这个宏的哪一部分是表达式,以及表达式停止和 ] -> 出现的位置是明确的,即使面对未来的语言扩展。