---
title: プロシージャルマクロ (Procedural Macros)
url: https://doc.liz6.com/ja/rust/08-macro-system/02-procedural-macros
locale: ja
area: rust
tags:
- rust
- macro-system
date: 2026-06-30
modified: 2026-07-16
description: プロシージャルマクロはコンパイル時にRustコードを実行し、TokenStreamを受け取ってTokenStreamを出力します。deriveマクロはstruct/enumに対してimplを自動生成し、attributeマクロは任意の項目を修飾し、function-likeマクロは関数のように呼び出されますがトークンストリームを処理します。synはTokenStreamをASTに解析し、quoteはASTをTokenStreamに戻し、cargo expandは展開結果を確認します。これらはプロシージャルマクロを書くための標準的なワークフローです。
---

# プロシージャルマクロ (Procedural Macros)

> プロシージャルマクロはコンパイル時にRustコードを実行し、TokenStreamを受け取ってTokenStreamを出力します。deriveマクロはstruct/enumに対してimplを自動生成し、attributeマクロは任意の項目を修飾し、function-likeマクロは関数のように呼び出されますがトークンストリームを処理します。synはTokenStreamをASTに解析し、quoteはASTをTokenStreamに戻し、cargo expandは展開結果を確認します。これらはプロシージャルマクロを書くための標準的なワークフローです。

## 3種類のプロシージャルマクロ

```rust
// 1. derive: #[derive(MyTrait)] — 型に対してimplを自動生成
#[proc_macro_derive(MyTrait)]
pub fn my_derive(input: TokenStream) -> TokenStream { ... }

// 2. attribute: #[my_attr] — 項目全体 (fn, struct, impl) を修飾
#[proc_macro_attribute]
pub fn my_attr(attr: TokenStream, item: TokenStream) -> TokenStream { ... }

// 3. function-like: my_macro!(...) — macro_rules! に似ているが、Rust関数で入力を処理
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream { ... }
```

プロシージャルマクロはRustコードであり、コンパイル時に実行され、`TokenStream`（トークンのシーケンス）を受け取って生成します。これは `macro_rules!` よりも柔軟性が高く、任意の複雑なコンパイル時の計算を行うことができます。

## syn + quote: 事実上の標準

```rust
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};
use quote::quote;

#[proc_macro_derive(Hello)]
pub fn hello_derive(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);   // TokenStream → AST
    let name = input.ident;
    let gen = quote! {
        impl Hello for #name {
            fn hello() { println!("Hello, {}!", stringify!(#name)); }
        }
    };
    gen.into()                                               // TokenStreamに戻る
}
```

`syn` は `TokenStream` を AST（Rustコンパイラのフロントエンドのようなもの）に解析します。`quote!` はRustコードをトークンストリームに戻し、補間（`#name`）をサポートします。

## proc-macro crate の制限

- 別のcrateでなければならない（`Cargo.toml`: `[lib] proc-macro = true`）
- procマクロ関数のみをエクスポートでき、通常の関数、型、定数はエクスポートできない
- 依存関係にサイクルを含めることはできない——proc-macro crate は他のcrateに依存できるが、同じワークスペースのcrateから逆依存されることはできない

## cargo expand: マクロの展開

```bash
cargo install cargo-expand
cargo expand                          # 現在のcrateのすべてのマクロを展開
cargo expand my_function              # 特定の関数のみ展開
```

マクロの動作を理解するための最速の方法です——コンパイラが実際に処理しているコードを見ることができます。

## 参考

- **syn**: docs.rs/syn, **quote**: docs.rs/quote
- **cargo-expand**: github.com/dtolnay/cargo-expand

*キーワード: proc macro, derive, syn, quote, TokenStream, cargo expand, attribute macro, function-like macro*
