在 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));
}
我想知道为什么,如果我可以使用 ,
以外的分隔符?
最佳答案
不确定您是否使用不同的 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.
它包括可用于各种片段说明符的分隔符:
expr
和stmt
后面只能跟以下之一:=>
、、
或;
.pat_param
后面只能跟以下之一:=>
、、
、=
、|
、if
或in
。pat
后面只能跟以下之一:=>
、、
、=
、if
,或in
。path
和ty
后面只能跟以下之一:=>
、、
、=
、|
、;
、:
、>
、>>
、[
、{
、as
、where
或block
的宏变量> 片段说明符。vis
后面只能跟以下之一:、
、非原始priv
以外的标识符、可以开头的任何标记类型或带有ident
、ty
或path
片段说明符的元变量。- 所有其他片段说明符都没有限制。
关于rust - 我是否可以在 Rust 的 MacroMatch 中使用逗号以外的分隔符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72921661/