宏规则中的“或”模式

总结

  • 模式在 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
	} 
}
}