宏规则中的“或”模式
总结
- 模式在
macro_rules
宏中的工作方式略有变化macro_rules
中的$_:pat
现在也匹配|
的使用:例如A | B
。- 新的
$_:pat_param
的行为类似于之前的$_:pat
;它不匹配(顶层)|
。 $_:pat_param
在所有版本中均可用。
详情
从 Rust 1.53.0 开始,模式 已扩展为支持嵌套在模式中任何位置的 |
。这使您能够编写 Some(1 | 2)
而不是 Some(1) | Some(2)
。由于这在以前根本不允许,因此这不是一个破坏性更改。
但是,此更改也会影响 macro_rules
宏。此类宏可以使用 :pat
片段说明符接受模式。目前,:pat
不 匹配顶层 |
,因为在 Rust 1.53 之前,并非所有模式(在所有嵌套级别)都可以包含 |
。接受 A | B
等模式的宏,例如 matches!()
使用类似 $($_:pat)|+
的内容。
因为这可能会破坏现有的宏,所以 :pat
的含义在 Rust 1.53.0 中没有更改为包含 |
。相反,该更改发生在 Rust 2021 中。在新版本中,:pat
片段说明符将 匹配 A | B
。
Rust 2021 中的 $_:pat
片段不能后跟显式 |
。由于有时仍然希望匹配后跟 |
的模式片段,因此添加了片段说明符 :pat_param
以保留旧的行为。
重要的是要记住,版本是按箱子划分的,因此唯一相关的版本是定义宏的箱子的版本。使用宏的箱子的版本不会改变宏的工作方式。
迁移
每当使用 $_:pat
时,都会触发 rust_2021_incompatible_or_patterns
lint,这将在 Rust 2021 中改变其含义。
您可以通过运行以下命令自动将代码迁移到与 Rust 2021 版本兼容,或确保代码已兼容:
cargo fix --edition
如果您的宏依赖于 $_:pat
不匹配模式中 |
的顶层使用,则需要将每次出现的 $_:pat
更改为 $_:pat_param
。
例如
#![allow(unused)] fn main() { macro_rules! my_macro { ($x:pat | $y:pat) => { // TODO: implementation } } // This macro works in Rust 2018 since `$x:pat` does not match against `|`: my_macro!(1 | 2); // In Rust 2021 however, the `$_:pat` fragment matches `|` and is not allowed // to be followed by a `|`. To make sure this macro still works in Rust 2021 // change the macro to the following: macro_rules! my_macro { ($x:pat_param | $y:pat) => { // <- this line is different // TODO: implementation } } }