問題
コンパイルを実行した際に、Rustがマクロが存在しないと主張することがあります。これは通常、serde_json::json!のような人気のあるマクロや、ローカルのmacro_rules!ブロックを呼び出すときに発生します。マクロはコンパイラが他のコードを解決する前に展開されるため、標準的な関数よりも厳格なスコープルールに従います。
// このスニペットはエラーを発生させます
fn main() {
// エラー: このスコープにマクロ `json` が見つかりません
let my_data = json!({ "key": "value" });
}
主な原因と修正方法
1. 外部マクロのインポート漏れ
Rust 1.31(Edition 2018)のリリース以降、マクロは標準的なアイテムと同じように振る舞うようになりました。レガシーなextern crateブロックですべてを囲む必要はもうありません。しかし、依然としてマクロを現在のファイルのスコープに取り込む必要があります。
修正方法: モジュールの先頭で明示的なuse文を使用します。これがserdeやtokioのような依存関係を処理する最もクリーンな方法です。
use serde_json::json;
fn main() {
let my_data = json!({ "status": 200 }); // 正常に動作します
}
2. 「上から下へ」の定義ルール
Rustはmacro_rules!を逐次的に処理します。main.rsの最後でマクロを定義し、それを上部の関数で呼び出そうとすると、コンパイラは失敗します。まだ定義に到達していないためです。
// ❌ これは失敗します
fn main() {
say_hello!();
}
macro_rules! say_hello {
() => { println!("こんにちは!"); };
}
修正方法: マクロの定義を、それを呼び出すコードよりも上に移動します。Rustでは、同一ファイル内のマクロについては順序が重要です。
macro_rules! say_hello {
() => { println!("こんにちは!"); };
}
fn main() {
say_hello!(); // 修正済み: コンパイラが先に定義を確認しました
}
3. モジュール境界を越えたマクロのエクスポート
pubのような標準的な可視性キーワードはmacro_rules!には適用されません。src/utils.rsでマクロを定義し、それをsrc/main.rsで使用したい場合は、別の方法が必要です。
修正方法: #[macro_export]属性を適用します。これにより、マクロが公開され、クレートのルートに配置されます。
// src/my_macros.rs
#[macro_export]
macro_rules! debug_log {
($msg:expr) => { println!("[DEBUG]: {}", $msg); };
}
// src/main.rs
mod my_macros;
fn main() {
// クレートルート経由でアクセスします
crate::debug_log!("システムが初期化されました");
}
4. 内部モジュールでの #[macro_use] の使用
毎回crate::プレフィックスを使用したくない場合は、モジュール宣言で#[macro_use]を使用することで、子モジュールのすべてのマクロを親スコープに取り込むことができます。
// src/main.rs
#[macro_use]
mod my_macros;
fn main() {
// プレフィックスなしで使用可能になります
debug_log!("ローカルで動作します");
}
確認方法
ターミナルでクイックチェックを実行して、進捗を確認してください。
cargo check
このコマンドはコード生成をスキップするため、フルビルドよりも高速です。VS Codeを使用している場合、正しいuse文または#[macro_export]文を記述してファイルを保存すると、rust-analyzer拡張機能が赤いエラー表示をすぐに消してくれるはずです。
クイックサマリー
- 語彙的順序: 同一ファイル内では、呼び出す前にマクロを定義してください。
- 可視性: 異なるファイル間でマクロを共有するには
#[macro_export]を使用してください。 - モダンなスタイル: ネームスペースを整理するために、外部クレートに対してはレガシーな
#[macro_use]よりもuse crate_name::macro_nameを優先してください。

