---
title: 宣言的マクロ (macro_rules!)
url: https://doc.liz6.com/ja/rust/08-macro-system/01-declarative-macros-macro-rules
locale: ja
area: rust
tags:
- rust
- macro-system
date: 2026-06-30
modified: 2026-07-16
description: macro_rules! はパターンマッチングと反復を用いてマクロを定義します——$($x:expr),* は、カンマ区切りの式がゼロ個以上あることを表します。フラグメント指定子（expr/ty/ident/tt）はマッチする構文断片のタイプを制限し、tt muncher は可変引数マクロを実装するための高度なテクニックです。宣言的マクロと関数の違い：マクロはコンパイル時に AST ノードに展開され、関数は実行時に呼び出されます——マクロは関数ではできない構文レベルの抽象化を実現できます。
---

# 宣言的マクロ (macro_rules!)

> `macro_rules!` はパターンマッチングと反復を用いてマクロを定義します——`$($x:expr),*` は、カンマ区切りの式がゼロ個以上あることを表します。フラグメント指定子（expr/ty/ident/tt）はマッチする構文断片のタイプを制限し、tt muncher は可変引数マクロを実装するための高度なテクニックです。宣言的マクロと関数の違い：マクロはコンパイル時に AST ノードに展開され、関数は実行時に呼び出されます——マクロは関数ではできない構文レベルの抽象化を実現できます。

## macro_rules! は関数ではない

```rust
macro_rules! vec {
    ( $( $x:expr ),* ) => {                                    // マッチパターン
        {
            let mut temp_vec = Vec::new();
            $( temp_vec.push($x); )*                             // 展開パターン
            temp_vec
        }
    };
}
```

マクロと関数の根本的な違い：マクロは**コンパイル時にコードに展開**されます（実行時の呼び出しではありません）。これは、マクロが可変長引数を受け取ったり、異なるタイプのコードを生成したり、識別子を生成したりできることを意味します。これらは関数では実現できません。

## フラグメント指定子：マクロの「型システム」

| 指定子 | マッチ対象 | 例 |
|-----------|------|------|
| `:expr` | 任意の式 | `42`, `x + y`, `{ ... }` |
| `:ident` | 識別子 | `my_var`, `HashMap` |
| `:ty` | 型 | `i32`, `Vec<String>` |
| `:tt` | 任意のトークン木 | 最も汎用的で、高度なマクロの構築に使用 |
| `:literal` | リテラル | `1`, `"hello"`, `true` |
| `:pat` | パターン | `Some(x)`, `1..=10` |
| `:path` | パス | `std::collections::HashMap` |
| `:block` | ブロック | `{ stmt1; stmt2; }` |
| `:stmt` | 文 | `let x = 1;`, `x;` |
| `:item` | 項目 | `fn f() {}`, `struct S;` |
| `:meta` | 属性の内容 | `derive(Debug)` |

## 反復パターン

```rust
$( $key:expr => $value:expr ),*    $(,)?       # 任意の末尾のコンマ
```

- `*`: 0回以上
- `+`: 1回以上
- `?`: 0回または1回（任意）

## tt Muncher: トークン木の再帰処理

最も強力なマクロパターン——再帰と `:tt` を用いて任意に複雑な入力を処理します：

```rust
macro_rules! html {
    ($text:expr) => { format!("{}", $text) };
    (<$tag:ident> $($children:tt)* </$tag:ident>) => {
        format!("<{}>{}</{}>", stringify!($tag),
                html!($($children)*),            // 子要素を再帰的に展開！
                stringify!($tag))
    };
}
let s = html!(<div> "hello" <span> "world" </span> </div>);
// → "<div>hello<span>world</span></div>"
```

tt muncher の原理：各マクロ呼び出しで `<tag> ... </tag>` パターンにマッチし、その後 `$children` を再帰的に展開します。これは proc macro を必要とせず、純粋な macro_rules! のみで実現可能です。

## 参考

- **Little Book of Rust Macros**: danielkeep.github.io/tlborm
- **Rust Book**: 第19章 5節 — マクロ

*キーワード: macro_rules!, 宣言的マクロ, 反復, tt muncher, フラグメント指定子, コンパイル時展開*
