plugins/languages/rust/skills/macros/SKILL.md
Rust 宏开发规范 — `macro_rules!` 声明宏(卫生性、完整路径、递归 / 重复模式)、过程宏(derive / 属性 / 函数式)、proc-macro2 + syn 2.x + quote 工具链、trybuild 编译测试、cargo-expand 展开验证、`compile_error!` span 精确报错。设计宏 API、实现 derive 宏、做代码生成 / 元编程时加载。触发短语:macro_rules、proc-macro、derive 宏、属性宏、syn、quote、代码生成、宏展开、元编程。
npx skillsauth add lazygophers/ccplugin rust-macrosInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
前置:rust-core。
| 需求 | 方案 |
|------|------|
| 简单重复模式(DSL) | macro_rules! |
| 自动实现 trait | derive 过程宏 |
| 改装函数 / 结构体 | 属性过程宏 |
| 函数式 DSL | 函数式过程宏 |
| 首选 | 泛型 + trait 解决,无法解决再宏 |
宏是代码生成器,不是抽象工具。能用类型系统解决的问题禁止上宏。
macro_rules! 模板macro_rules! hashmap {
($($k:expr => $v:expr),* $(,)?) => {{
let mut m = ::std::collections::HashMap::new();
$(m.insert($k, $v);)*
m
}};
}
let m = hashmap! { "a" => 1, "b" => 2, };
卫生性铁律:宏内引用 std / 第三方类型必须用 ::std::... / ::serde::... 完整路径,避免调用方命名空间污染。
Cargo.toml:
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1"
syn = { version = "2", features = ["full"] }
quote = "1"
Derive 宏示例:
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Data, Fields};
#[proc_macro_derive(Builder)]
pub fn derive_builder(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let name = &ast.ident;
let builder = syn::Ident::new(&format!("{name}Builder"), name.span());
let fields = match &ast.data {
Data::Struct(s) => match &s.fields {
Fields::Named(f) => &f.named,
_ => return syn::Error::new_spanned(name, "Builder requires named fields")
.to_compile_error().into(),
},
_ => return syn::Error::new_spanned(name, "Builder requires struct")
.to_compile_error().into(),
};
let setters = fields.iter().map(|f| {
let n = &f.ident; let t = &f.ty;
quote! { pub fn #n(mut self, v: #t) -> Self { self.#n = Some(v); self } }
});
quote! {
impl #builder {
#(#setters)*
}
}.into()
}
属性宏(函数包装):
#[proc_macro_attribute]
pub fn timed(_attr: TokenStream, item: TokenStream) -> TokenStream {
let f = parse_macro_input!(item as syn::ItemFn);
let sig = &f.sig; let block = &f.block; let vis = &f.vis;
let name = &sig.ident;
quote! {
#vis #sig {
let _t = ::std::time::Instant::now();
let _r = (|| #block)();
::tracing::info!(fn = stringify!(#name), elapsed_ms = _t.elapsed().as_millis());
_r
}
}.into()
}
宏内部禁止 panic!;用 syn::Error::new_spanned(...).to_compile_error() 在出错位置给出 IDE 友好提示。
return syn::Error::new_spanned(field, "expected `#[builder(default)]`")
.to_compile_error().into();
// trybuild:验证编译通过 / 失败
#[test]
fn ui() {
let t = trybuild::TestCases::new();
t.pass("tests/expand/*.rs");
t.compile_fail("tests/fail/*.rs");
}
cargo expand --test <name> 验证展开结果,作为开发期 review 工具。
| AI 倾向 | 正确做法 |
|---------|---------|
| 万物皆可宏 | 先用泛型 + trait |
| syn 1.x | 升级到 syn 2.x |
| panic! 报错 | Error::to_compile_error |
| 宏内裸 String | 完整路径 ::std::string::String |
| 不写测试 | trybuild + cargo expand |
macro_rules! 使用 :: 完整路径syn 2.x + quotesyn::Error::to_compile_error 而非 panic!trybuild 编译测试development
Go 数据库规范——GORM Model 命名 ModelXxx、表名单数、枚举 uint8 + 常量、索引 idx_ 前缀 + deleted_at leading column、禁 time.Time 统一 int64 unix、禁指针/nullable 字段、TEXT/BLOB/JSON 禁 default、AutoMigrate 禁改主键。设计 DB model、写 GORM tag、建索引、做 migration 审查时触发。
development
Go HTTP API 规范——响应始终 200 + body code 字段、路由 /api/* 全 POST 单段 <Action><Model>、中间件逐路由注册禁 Group(prefix,mw...)、handler 仅返回 (rsp,error)、认证走 header。设计 HTTP API、写路由/handler/中间件时触发。
development
Go 项目结构规范——三层架构(API → Impl → State)、全局状态模式、internal/ 私有包、cmd/ 仅 main.go、go.work 多模块、禁止 Repository 接口和 DI 容器、struct 公共字段开头全 omitempty、handler var rsp 顶声明、禁 legacy migration。设计项目骨架、新建目录、组织包、做架构评审时触发。
development
Go 命名规范——Id/Uid 字段(非 ID)、IsActive/HasMFA 布尔前缀、CreatedAt 时间字段、接收者统一用 p、包名全小写无下划线、泛型类型参数描述性命名、集合字段 xxx_list 禁 xxxs 复数、Enum 0 值 XxxNil 禁 Unknown、禁 Status 统一 State、Set/Update 语义区分。定义结构体字段、函数、变量、包、接收者名、泛型、枚举时触发。