macro_rules!
Rustはメタプログラミングを可能にする、パワフルなマクロシステムを備えています。これまで見てきたように、マクロは!
で終わることを除けば関数のように見えます。関数と違うのは関数呼び出しを生成する代わりに、ソースコード中に展開され、周囲のプログラムとともにコンパイルされる点です。しかし、Cやその他の言語のマクロが文字列のプリプロセッシングをするのと異なり、Rustのマクロは抽象構文木へと展開されるので、予期せぬ演算子の優先順位のバグに出くわすことがありません。
マクロを作成するにはmacro_rules!
というマクロを使用します。
// `say_hello`という名のシンプルなマクロ macro_rules! say_hello { // `()`はマクロが引数をとらないことを示します。 () => { // マクロは(訳注: プリコンパイルの段階で) // このブロックの内容に展開されます。 println!("Hello!") }; } fn main() { // この呼び出しは`println!("Hello!");`に置き換えられます。 say_hello!() }
ではどうしてマクロは便利なのでしょうか?
-
同じことを繰り返し書いてはいけないから。複数の場所で、別の型だけれど似たような機能が必要な時がよくあります。しばしば、マクロはコードを繰り返し書くのを避ける有用な手段なのです(あとで詳述)。
-
ドメイン特化言語であるから。マクロを使うと、特定の目的のための特定の構文を定義することができます(あとで詳述)。
-
可変個引数によるインターフェース。取る引数の数が可変であるようなインターフェースを定義したくなることもあるでしょう。例えば、
println!
は、フォーマット文字列に依存した任意の数の引数を取ることができます(あとで詳述)!