この記事は Rustその3 Advent Calendarの10日目の記事です。空いていたのでちょっとしたツールをご紹介します。
Rustのマクロについて
Rustのマクロは、Rustの他の要素と比べて変わった文法なので最初は戸惑うかもしれません。しかし、やっていることは「どういう構文にマッチするのかを定義する」「その構文がコンパイル時にどう変換されるか定義する」の2つです。このうち、前者の「どういう構文にマッチするのか」がイメージしやすくなれば、マクロを書きやすくなるでしょう。というわけで、この部分を可視化します。
railroad
railroadは、その名の通り鉄道の線路のようにマクロの構文を可視化してくれます。ありがたいことに、Webブラウザで動くデモがありますので、以下から使わせてもらいます。
試しに、頻繁に使うマクロであるvec!
を可視化してみます。vec!
の定義は以下の通りです。置換後の内容は今回は関係ないので、{ ... }
と省略してあっても問題ありません。
macro_rules! vec {
($ elem : expr ; $ n : expr) => { ... };
($ ($ x : expr), *) => { ... };
($ ($ x : expr,) *) => { ... };
}
これを上記のサイトのエディタにコピペすると、以下のような画像が生成されます。
vec!
の書き方は、値と要素数の組、もしくは要素の繰り返しで最後の","が必要かどうか、の3つに分かれていることが視覚的にわかります。また凡例から、elem,n,xはexpression(式)であることがわかります。
もう少し複雑なものでもいけます。例えばlazy_static!
なら以下のような定義になります。
macro_rules! lazy_static {
($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { ... };
($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { ... };
($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { ... };
() => { ... };
}
そして生成される画像は以下のようになります。
おわりに
以上のようにマクロの構文を可視化することができました。自作のマクロを作成している時や、使い方のよくわからないマクロがあった時もこれでイメージしやすくなると思います。