rust - 我是否可以在 Rust 的 MacroMatch 中使用逗号以外的分隔符?

标签 rust

rust book我看到MacroMatch的定义如下

MacroMatch :
      Token except $ and delimiters
   | MacroMatcher
   | $ ( IDENTIFIER_OR_KEYWORD except crate | RAW_IDENTIFIER | _ ) : MacroFragSpec
   | $ ( MacroMatch+ ) MacroRepSep? MacroRepOp

MacroFragSpec :
      block | expr | ident | item | lifetime | literal
   | meta | pat | pat_param | path | stmt | tt | ty | vis

MacroRepSep :
   Token except delimiters and MacroRepOp

MacroRepOp :
   * | + | ?

根据tokens的定义,我发现 >> 是一个 token 。因此,根据我的理解,我们可以使用除 {}/[]/{}/*< 之外的所有标记作为 MacroRepSep//+/?。 但是下面的代码无法编译,报错“$a:expr后面是>>,这是expr不允许的” > 碎片”

macro_rules! add_list2 {
    ($($a:expr)>>*) => {
        0
        $(+$a)*
    }
}

pub fn main() {
    println!("{}", add_list!(1>>2>>3));
}

Playground .

我想知道为什么,如果我可以使用 , 以外的分隔符?

最佳答案

不确定您是否使用不同的 Rust 版本,但使用当前编译器 (1.62) 上的代码,它会输出一个错误,其中包括可用的分隔符:

error: `$a:expr` is followed by `>>`, which is not allowed for `expr` fragments
 --> src/main.rs:2:16
  |
2 |     ($($a:expr)>>*) => {
  |                ^^ not allowed after `expr` fragments
  |
  = note: allowed there are: `=>`, `,` or `;`

expr 上重复的问题在于,由于它们变化很大,它们很容易出现歧义,或者可能变得歧义。我将引用 Follow-set Ambiguity Restrictions 上的部分:

The parser used by the macro system is reasonably powerful, but it is limited in order to prevent ambiguity in current or future versions of the language. In particular, in addition to the rule about ambiguous expansions, a nonterminal matched by a metavariable must be followed by a token which has been decided can be safely used after that kind of match.

As an example, a macro matcher like $i:expr [ , ] could in theory be accepted in Rust today, since [,] cannot be part of a legal expression and therefore the parse would always be unambiguous. However, because [ can start trailing expressions, [ is not a character which can safely be ruled out as coming after an expression. If [,] were accepted in a later version of Rust, this matcher would become ambiguous or would misparse, breaking working code. Matchers like $i:expr, or $i:expr; would be legal, however, because , and ; are legal expression separators.

它包括可用于各种片段说明符的分隔符:

  • exprstmt 后面只能跟以下之一:=>;.
  • pat_param 后面只能跟以下之一:=>= |ifin
  • pat 后面只能跟以下之一:=>= if,或in
  • pathty 后面只能跟以下之一:=> =|;:>>>[{aswhereblock 的宏变量> 片段说明符。
  • vis 后面只能跟以下之一:、非原始 priv 以外的标识符、可以开头的任何标记类型或带有 identtypath 片段说明符的元变量。
  • 所有其他片段说明符都没有限制。

关于rust - 我是否可以在 Rust 的 MacroMatch 中使用逗号以外的分隔符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72921661/

相关文章:

rust - 是否可以使一种类型只能移动而不能复制?

networking - Rust 中的 UDP API

generics - 如果我已经将特征边界添加到另一个 impl block ,为什么还需要在 impl block 上添加特征边界?

git - 如何检查 HEAD 是否被标记

rust - GtkEventBox 将信号连接到 Glade 中的 GAction

generics - 如何告诉编译器内部字段实现了特征或通用特征只有 2 个变体?

rust - Rust 程序如何从其 Cargo 包中访问元数据?

rust - 如何在不必处理生命周期的情况下存储引用?

rust - 不安全代码中可变引用的别名是否正确?

rust - 为什么从 struct 切换到 enum 会破坏 API?