「用 macro! 实现逆波兰表达式」验证结果

「这是我参与11月更文挑战的第 21 天,活动详情查看:2021最后一次更文挑战


现在,任何词都被相应的分支处理,我们只需要处理最后的情况,即栈包含一个项目,并且没有更多的词了。

1
2
3
4
5
6
7
rust复制代码macro_rules! rpn {
// ...

([ $result:expr ]) => {
$result
};
}

此时,如果你用一个空的栈和RPN表达式来调用这个宏,它已经会产生一个正确的结果。

Playground

1
rust复制代码println!("{}", rpn!([] 2 3 + 4 *)); // 20

然而,我们的栈是一个实现细节,我们真的不希望每个消费者都传入一个空的堆栈,所以让我们在最后再添加一个接续分支,作为一个入口点,并自动添加[]。

Playground

1
2
3
4
5
6
7
8
9
rust复制代码macro_rules! rpn {
// ...

($($tokens:tt)*) => {
rpn!([] $($tokens)*)
};
}

println!("{}", rpn!(2 3 + 4 *)); // 20

我们的宏甚至适用于更复杂的表达式。

1
rust复制代码println!("{}", rpn!(15 7 1 1 + - / 3 * 2 1 1 + + -)); // 5

那如果出错了怎么办?现在,对于正确的RPN表达式来说,一切似乎都工作得很顺利,但对于一个可以投入生产的宏来说,我们需要确保它也能处理无效的输入,并且有合理的错误信息。

首先,让我们试着在中间插入另一个数字,看看会发生什么:

1
rust复制代码println!("{}", rpn!(2 3 7 + 4 *));

输出:

1
2
3
4
5
6
7
8
rust复制代码error[E0277]: the trait bound `[{integer}; 2]: std::fmt::Display` is not satisfied
--> src/main.rs:36:20
|
36 | println!("{}", rpn!(2 3 7 + 4 *));
| ^^^^^^^^^^^^^^^^^ `[{integer}; 2]` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
|
= help: the trait `std::fmt::Display` is not implemented for `[{integer}; 2]`
= note: required by `std::fmt::Display::fmt`

好吧,这个输出看起来没有帮助,因为它没有提供任何与表达式中的实际错误相关的信息。

为了弄清发生了什么,我们需要对我们的宏进行调试。为此,我们将使用 trace_macros 功能(和其他可选的编译器功能一样,你需要一个Rust nightly版本)。我们不想跟踪 println! 调用,所以我们将把我们的RPN计算分离到一个变量中。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%