マクロ規則における OR パターン
概要
macro_rules
におけるパターンの挙動がほんの少し変更されました:macro_rules
において、$_:pat
で|
を使ったパターンにもマッチするようになりました。例えば、A | B
にマッチします。- 新しく導入された
$_:pat_param
は、かつての$_:pat
と同じ挙動を再現します。すなわち、こちらは(トップレベルの)|
にはマッチしません。 $_:pat_param
は全てのエディションで使用可能です。
詳細
Rust 1.53.0 から、パターン中のどこでも、|
をネストして使えるようになりました。
これにより、Some(1) | Some(2)
でなく Some(1 | 2)
と書くことができるようになりました。
今まではこうは書けなかったので、これは破壊的変更ではありません。
ところが、この変更は macro_rules
で定義されたマクロ にも影響します。
macro_rules
では、:pat
というフラグメント指定子で、パターンを受け付けることができます。
現在のところ、:pat
はトップレベルの |
にマッチしません。
なぜなら Rust 1.53 以前は、全てのパターンが(どのネストレベルにでも)|
を含むことができるわけではなかったからです。
matches!()
のように、
A | B
のようなパターンを受け付けるマクロを書くには、
$($_:pat)|+
のような書き方をしなくてはなりませんでした。
既存のマクロを壊す可能性があるため、Rust 1.53.0 では :pat
が |
を含むことができるようには変更されませんでした。
代わりに、Rust 2021 で変更がなされました。
新しいエディションでは、:pat
フラグメント指定子は A | B
にマッチします。
Rust 2021 では、$_:pat
フラグメントに |
そのものを続けることはできません。
パターンフラグメントに |
が続いてるものにマッチさせたいような場合は、新しく追加された :pat_param
が過去と同じ挙動を示すようになっています。
ただし、エディションはクレートごとに設定されることに注意してください。 つまり、マクロが定義されているクレートのエディションだけが関係します。 マクロを使用する方のクレートのエディションは、マクロの挙動に影響しません。
移行
$_:pat
が使われている場所のうち、Rust 2021 で意味が変わるようなものに対しては、rust_2021_incompatible_or_patterns
というリントが発生します。
コードを自動的に Rust 2021 エディションに適合するよう自動移行するか、既に適合するものであることを確認するためには、以下のように実行すればよいです:
cargo fix --edition
あなたのマクロが、$_:pat
がトップレベルの |
にマッチしないという挙動に依存している場合は、
$_:pat
を $_:pat_param
に書き換える必要があります。
例えば以下のようになります。