背景情報

マクロではソースコードからソースコードの自動生成が行われる。

この生成内容を確認できると、いくらかデバッグが簡単になる。

解決策

以下を状況によって使い分けるとよい。

rust-analyzer
手軽な普段使いに最適
cargo expand
実行コードの入手に最適

rust-analyzer

rust-analyzer にはこのための専用機能がある。

長所と短所

  • 手軽に実行できる。
  • 展開結果に $crate などの展開前のコードが混ざる事がある。

実行手順

VS Code からの場合、以下の手順で実行できる。

  1. キャレットをマクロの呼出箇所へ移動
  2. コマンドパレットを起動 (Ctrl+Shift+P を押下)
  3. "rust-analyzer: Expand macro recursively at caret" を選択
  4. 新規タブに表示される展開結果を確認

サンプル

以下のコードの vec! の箇所で前述の操作を行うと…。


fn main() {
    let words = vec!["Hello", "macro", "world"];
    println!("{}", words.join(" "));
}

以下のような展開結果が表示される。


// Recursive expansion of vec! macro
// ==================================

(<[_]>::into_vec(
    #[rustc_box]
    $crate::boxed::Box::new(["Hello", "macro", "world"]),
))

cargo expand

cargo expand コマンドも使える。

長所と短所

  • 実行可能なコードを取得できる。
  • 処理対象が最低でも関数単位のため小回りが効かない。
  • エラーが早期に検出されると展開が打ち切られる事がある。

実行手順

crates.io から cargo-expand をインストールして cargo を拡張する。


> cargo install cargo-expand

コマンドを実行する (以下は前述の例の main 関数を対象にした場合)。


> cargo expand main 

サンプル

以下のような展開結果が表示される。


fn main() {
    let words = <[_]>::into_vec(
        #[rustc_box]
        ::alloc::boxed::Box::new(["Hello", "macro", "world"]),
    );
    {
        ::std::io::_print(format_args!("{0}\n", words.join(" ")));
    };
}