マクロ規則における 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
に書き換える必要があります。
例えば以下のようになります。
#![allow(unused)] fn main() { macro_rules! my_macro { ($x:pat | $y:pat) => { // TODO: implementation // TODO: 実装 } } // This macro works in Rust 2018 since `$x:pat` does not match against `|`: // Rust 2018 では、`$x:pat` が `|` にマッチしないので、以下のマクロは正常に動きます: 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: // 一方 Rust 2021 では、`$_:pat` フラグメントは `|` にもマッチし、 // `|` が続くのは許されなくなりました。 // Rust 2021 でもマクロが動作するためには、マクロを以下のように変更しなくてはなりません: macro_rules! my_macro { ($x:pat_param | $y:pat) => { // <- this line is different // この行を変えた // TODO: implementation // TODO: 実装 } } }