TL;DR

  • derive マクロは入力のトークンを置き換えず、生成したコードを追加する。データ構造の定義はそのまま残る。
  • derive マクロはヘルパ属性を宣言できる。入力のトークン列のパースは、ほとんど syn クレートに任せられる。

内容

項目28 分別をもってマクロを使おうのうち、derive マクロを使うときの注意点である。

コードを追加する

derive マクロは、入力のトークンを置き換えるのではなく、生成したコードを追加する。つまり、付けた先のデータ構造の定義は変わらない。

ヘルパ属性

derive マクロは、関連するヘルパ属性(helper attributes)を宣言できる。たとえば serde の Deserialize derive マクロは、serde というヘルパ属性を持つ。この属性が、デシリアライズの処理を制御するためのメタデータになる。

fn generate_value() -> String {
    "unknown".to_string()
}
 
#[derive(Debug, Deserialize)]
struct MyData {
    // デシリアライズ時に `value` がなければ、`generate_value` の結果を入れる
    #[serde(default = "generate_value")]
    value: String,
}

入力のパース

入力のトークン列をパースして AST のノードにする作業は、大半を syn クレートがやってくれる。たとえば syn::parse_macro_input! は、アイテムのトークン列を、proc_macro::TokenStream より扱いやすい syn::DeriveInput に変換する。

キーワード

自分の理解

元の定義を残したままコードを追加するところは、Decorator パターンのようなイメージである。