「这是我参与11月更文挑战的第 21 天,活动详情查看:2021最后一次更文挑战」
现在,任何词都被相应的分支处理,我们只需要处理最后的情况,即栈包含一个项目,并且没有更多的词了。
1 | rust复制代码macro_rules! rpn { |
此时,如果你用一个空的栈和RPN表达式来调用这个宏,它已经会产生一个正确的结果。
1 | rust复制代码println!("{}", rpn!([] 2 3 + 4 *)); // 20 |
然而,我们的栈是一个实现细节,我们真的不希望每个消费者都传入一个空的堆栈,所以让我们在最后再添加一个接续分支,作为一个入口点,并自动添加[]。
1 | rust复制代码macro_rules! rpn { |
我们的宏甚至适用于更复杂的表达式。
1 | rust复制代码println!("{}", rpn!(15 7 1 1 + - / 3 * 2 1 1 + + -)); // 5 |
那如果出错了怎么办?现在,对于正确的RPN表达式来说,一切似乎都工作得很顺利,但对于一个可以投入生产的宏来说,我们需要确保它也能处理无效的输入,并且有合理的错误信息。
首先,让我们试着在中间插入另一个数字,看看会发生什么:
1 | rust复制代码println!("{}", rpn!(2 3 7 + 4 *)); |
输出:
1 | rust复制代码error[E0277]: the trait bound `[{integer}; 2]: std::fmt::Display` is not satisfied |
好吧,这个输出看起来没有帮助,因为它没有提供任何与表达式中的实际错误相关的信息。
为了弄清发生了什么,我们需要对我们的宏进行调试。为此,我们将使用 trace_macros
功能(和其他可选的编译器功能一样,你需要一个Rust nightly版本)。我们不想跟踪 println!
调用,所以我们将把我们的RPN计算分离到一个变量中。
本文转载自: 掘金