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 パターンのようなイメージである。