如何在宏中匹配 Rust 的“if”表达式?
Posted
技术标签:
【中文标题】如何在宏中匹配 Rust 的“if”表达式?【英文标题】:How to match Rust's `if` expressions in a macro? 【发布时间】:2019-01-26 17:07:02 【问题描述】:我正在尝试编写一个将重写某些 Rust 控制流的宏,但我在匹配 if
表达式时遇到了困难。问题是谓词是一个表达式,但expr
后面不允许跟block
或。
我最好的方法是使用tt
:
macro_rules! branch
(
if $pred:tt
$r1:block
else
$r2:block
) =>
if $pred
$r1
else
$r2
;
这适用于单令牌或分组谓词:
branch!
if (foo == bar)
1
else
2
但如果谓词未分组则失败:
branch!
if foo == bar
1
else
2
error: no rules expected the token `==`
我还尝试在谓词中使用tt
的重复模式:
macro_rules! branch
(
if $($pred:tt)+
$r1:block
else
$r2:block
) =>
if $($pred)+
$r1
else
$r2
;
但这会产生错误,因为现在不确定后续块是否也应匹配tt
:
error: local ambiguity: multiple parsing options: built-in NTs tt ('pred') or block ('r1').
有没有办法做到这一点,还是我坚持发明特殊语法以在宏中使用?
【问题讨论】:
我不想消极,但是宏太乱了……我也没有匹配到一些 Rust 构造。 @Boiethios 我记得。我只需要发明特殊的语法,类似于您可能对您的问题所做的事情。 【参考方案1】:您可以使用TT muncher 来解析谓词:
macro_rules! branch
if $($rest:tt)*
=>
branch_parser!
predicate = ()
rest = ($($rest)*)
;
macro_rules! branch_parser
predicate = ($($predicate:tt)*)
rest = ( $($then:tt)* else $($else:tt)* )
=>
println!("predicate: ", stringify!($($predicate)*));
println!("then: ", stringify!($($then)*));
println!("else: ", stringify!($($else)*));
;
predicate = ($($predicate:tt)*)
rest = ($next:tt $($rest:tt)*)
=>
branch_parser!
predicate = ($($predicate)* $next)
rest = ($($rest)*)
;
fn main()
branch!
if foo == bar
1
else
2
输出:
predicate: foo == bar
then: 1
else: 2
【讨论】:
太棒了!请注意,它也可以在模式中没有predicate =
或 rest =
的情况下工作。后面的括号才是真正重要的。以上是关于如何在宏中匹配 Rust 的“if”表达式?的主要内容,如果未能解决你的问题,请参考以下文章