macro-rules 中的 Or 模式
摘要
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
以保留旧的行为。
重要的是要记住,版本是按 crate 划分的,因此唯一相关的版本是定义宏的 crate 的版本。使用宏的 crate 的版本不会更改宏的工作方式。
迁移
当存在 $_:pat
在 Rust 2021 中会改变含义的使用时,会触发一个 lint rust_2021_incompatible_or_patterns
。
您可以通过运行以下命令自动迁移您的代码以与 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 } } }