% インポート/エクスポート
マクロをより広いスコープに公開する方法は2つあります。1つ目は #[macro_use] 属性です。これはモジュールと外部クレートのどちらにも適用できます。例:
#[macro_use] mod macros { macro_rules! X { () => { Y!(); } } macro_rules! Y { () => {} } } X!(); fn main() {}
マクロは、#[macro_export] を使って現在のクレートからエクスポートできます。これはすべての可視性を無視することに注意してください。
ライブラリパッケージ macs に対して次の定義があるとします。
mod macros {
#[macro_export] macro_rules! X { () => { Y!(); } }
#[macro_export] macro_rules! Y { () => {} }
}
// X! と Y! はここでは定義されて*いません*が、
// `macros` がプライベートであるにもかかわらず、エクスポート*されています*。
次のコードは期待どおりに動作します。
X!(); // X は定義されている
#[macro_use] extern crate macs;
X!();
#
# fn main() {}
外部クレートに対して #[macro_use] できるのは、ルートモジュールからのみであることに注意してください。
最後に、外部クレートからマクロをインポートする場合、どのマクロをインポートするかを制御できます。これを使って名前空間の汚染を制限したり、次のように特定のマクロをオーバーライドしたりできます。
// `X!` マクロ*のみ*をインポートする。
#[macro_use(X)] extern crate macs;
// X!(); // X は定義されているが、Y! は未定義
macro_rules! Y { () => {} }
X!(); // X は定義されており、Y も定義されている!
fn main() {}
マクロをエクスポートする場合、定義元クレート内の非マクロシンボルを参照したいことがよくあります。クレートはリネームできるため、利用可能な特別な置換変数があります: $crate。これは、含んでいるクレートへの絶対パス接頭辞に常に展開されます(例 :: macs)。
これはマクロには機能しないことに注意してください。マクロはいかなる方法でも通常の名前解決と相互作用しないためです。つまり、クレート内の特定のマクロを参照するために $crate::Y! のようなものを使うことはできません。これが #[macro_use] による選択的インポートと組み合わさると、現在のところ、別のクレートによってインポートされたときに任意のマクロが利用可能になることを保証する方法はない、ということになります。
競合を避けるため、標準ライブラリ内の名前も含めて、非マクロ名には常に絶対パスを使うことが推奨されます。