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