マクロがどう展開されているのかを調べる(@Rust)

println!とかvec!はRustにおける頻繁に使われるマクロですが、マクロは多くの言語が持つ機能でそれはコンパイル時には展開されます。じゃRustのマクロがどのように展開されるか?を見るためのツールにcargo expandがあります。

https://crates.io/crates/cargo-expand

cargo initで作成されるmain.rsで見てみます。

<ソース>

fn main() {
    println!("Hello, world!");
}

マクロを含んだソースコードを対象にするならば、*.rsファイルの存在するディレクトリでcargo expandを実行します。

<展開後>

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
fn main() {
    {
        ::std::io::_print(format_args!("Hello, world!\n"));
    };
}

展開されたコード中には、さらにformat_args!というマクロが見えています、まあマクロからマクロは呼び出しできるから。

format_argsマクロを検索すると、以下のように記述されています。

https://doc.rust-lang.org/std/macro.format_args.html

macro_rules! format_args {
    ($fmt:expr) => { ... };
    ($fmt:expr, $($args:tt)*) => { ... };
}

という事で、引数がいくつかある場合にそれを展開してprint形式を作り出すマクロです。

 

実はcargo expandはパラメタ指定でソースコードではなくてバイナリからもマクロが展開されたソースコードの出力ができます。ソースコードからexpandしたものと全く同じに見えますが。

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
fn main() {
    {
        ::std::io::_print(format_args!("Hello, world!\n"));
    };
}

使い道はカスタムに作られたマクロのソースコード確認用になるでしょうか。

 

admin

カテゴリーRust