关于 rust-macros
面向 Rust 开发者的宏编写技能,涵盖声明式宏和过程宏的选择、实现与测试。它强调控制生成 API,并妥善处理展开结果、诊断信息和兼容性。
主要功能
- 01选择合适的宏类别
- 02处理声明式宏卫生性
- 03解析并生成过程宏代码
- 04管理诊断信息与 span
- 05测试宏展开和错误输入
适用场景
- 01判断是否适合使用宏
- 02实现 derive 或属性宏
- 03测试宏语法的接受与拒绝情况
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ full-stack-skills/ rust-skills --skill rust-macros安装后在 Claude Code 中输入/rust-macros确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlexamples/examples.mdexamples/golden-macro/Cargo.tomlexamples/golden-macro/src/lib.rsreferences/references.md详细介绍
Rust 宏
当语法转换或机械式生成无法通过函数、trait、泛型和构建脚本清晰实现时,使用宏。生成的 API 应比宏实现更精简、更稳定。
适用范围与路由
本技能适用于 macro_rules!、声明式 DSL、派生宏、属性宏、类函数过程宏、解析、令牌生成、卫生性、诊断和展开测试。
普通泛型设计请转至 rust-stable;crate 布局和过程宏配套 crate 请转至 rust-workspace;功能和发布策略请转至 rust-cargo-build;编译失败策略请转至 rust-testing;第三方类 Lombok 派生宏的使用请转至 rust-lombok-macros;UniFFI 导出/派生用法及生成的外部语言绑定请转至 rust-uniffi-building。
工作流
1. 确认宏是合适的边界
先编写有代表性的调用及预期展开结果。如果函数、trait、生态系统已提供的派生宏或少量手写实现能让诊断和代码导航更清晰,就优先采用这些方式。明确支持的语法、edition、MSRV、生成的名称、可见性、错误情况和 semver 影响范围。
2. 选择最精简的宏类别
| 需求 | 机制 |
|---|---|
| 重复或匹配 Rust 令牌模式 | macro_rules! |
| 为带注解的类型实现 trait | 派生过程宏 |
| 转换带注解的项 | 属性过程宏 |
| 解析自定义令牌调用 | 类函数过程宏 |
过程宏应使用专用的 proc-macro = true crate。将共享的运行时 trait 和类型放在普通库 crate 中,这样生成的代码就不会依赖过程宏实现的私有细节。
3. 根据公开接口为过程宏 crate 命名
将后缀视为 API 承诺,而非编译器要求:
| 公开的宏接口 | 建议的包后缀 | 示例 |
|---|---|---|
仅包含 #[proc_macro_derive] 入口 | -derive,或该系列既有的拼写形式,如 _derive | serde_derive |
| 更广泛的套件,尤其是包含属性宏或类函数宏,或混合多种宏类型 | -macros | tokio-macros、actix-macros |
| 宏的范围不明确或未指定 | 避免使用单数形式 -macro;选择更具描述性的名称 | — |
当所有公开入口都是派生宏时,选择 -derive。crate 可以公开多个密切相关的派生宏;决定因素是宏的类型,而非确切数量。当 crate 公开属性宏、类函数宏、混合多种宏类型,或有意作为该包系列的通用宏集合时,选择 -macros。
默认情况下,不要同时发布 <name>-derive 和 <name>-macros。单个过程宏 crate 可以注册任意数量的派生宏、属性宏和类函数宏。优先采用以下布局之一:
<name> # public runtime API or facade; may re-export macros
<name>-derive # derive-only proc-macro crate
<name> # public runtime API or facade; may re-export macros
<name>-macros # general proc-macro collection
<name>-macro-core # optional normal library for parsing and generation logic
仅当用户能够分别采用 -derive 和 -macros,且拆分能显著减少依赖或编译时间、区分发布或兼容性策略,或隔离不同的所有权边界时,才将它们拆分为单独发布的 crate。保持它们导出的宏名称和职责互不重叠。不要仅按宏类型拆分,也不要为了名称对称而拆分。
发布前还应:
- 遵循该 crate 系列已经使用的分隔符;Cargo 包名称可以包含
-或_,而 Rust crate 标识符会将连字符规范化为下划线。 - 如果大多数用户不应直接依赖实现 crate,优先使用门面 crate,并通过 feature 控制重新导出。
- 将已发布 crate 的重命名视为迁移,因为这会带来生态系统和 semver 成本;尽早确定长期适用范围,但不要声称计划支持尚未实现的宏类型。
4. 卫生地实现声明式宏
#[macro_export]
macro_rules! string_list {
($($value:expr),* $(,)?) => {{
let mut output = ::std::vec::Vec::new();
$(output.push(::std::string::ToString::to_string(&$value));)*
output
}};
}
- 将具体的匹配分支放在通用分支之前。
- 使用正确的片段说明符,例如
expr、ident、ty、pat、item、meta、path或tt。 - 仅在公开语法需要时支持可选的尾随分隔符。
- 使用
$crate引用定义该宏的 crate 中的路径。 - 避免重复求值、隐式移动、令人意外的控制流,以及与调用方代码冲突的标识符。
- 对于大量输入,避免使用具有二次复杂度的 TT muncher;若词元数量很重要,优先使用重复模式或过程式解析。
5. 以结构化方式解析过程宏
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(Describe)]
pub fn derive_describe(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
quote! {
impl Describe for #name {
fn type_name() -> &'static str {
stringify!(#name)
}
}
}
.into()
}
- 使用
syn或专门构建的解析器,而不是词元字符串。 - 保留跨度并合并
syn::Error值,以便用户收到多个有用的诊断信息。 - 当公开契约有此要求时,生成在依赖项重命名后仍可正常工作的路径。
- 保留泛型、生命周期、const 参数、where 子句、属性和可见性。
- 不要因无效的用户输入而 panic;应在相关跨度处生成编译错误。
6. 测试公开的展开契约
采用多个层次:
cargo fmt --all --check
cargo check --workspace --all-targets --all-features
cargo test --workspace --all-targets --all-features
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo expand --package example-crate
- 运行时测试和文档测试用例可证明生成的行为有效。
- 使用
trybuild或同等工具的 UI 测试,锁定接受和拒绝的语法以及诊断信息。 - 展开快照可辅助审查,但不能作为唯一的正确性门槛。
- 针对宏声称支持的泛型、生命周期、可见性、依赖项重命名、no-std、功能和 edition 组合进行测试。
Nightly 的 trace_macros! 是可选的诊断工具,不是稳定的默认方案。
阅读 宏参考,了解匹配器和过程宏的详细信息。阅读 执行场景,了解有代表性的请求。
审查清单
- 能否用函数、trait 或 derive 替代该宏?
- 调用方输入是否严格按照文档所述进行求值?
$crate、跨度、泛型和可见性是否处理正确?- 无效输入是否可能触发过程宏 panic?
- 生成的 unsafe 代码是否公开了有文档说明的安全契约?
- 是否测试了编译失败时的诊断,且没有对不稳定的措辞作过度限定?
- 生成的公开 API 是否会形成有意的 semver 承诺?
完成标准
- 在实现前定义支持的语法和预期展开结果。
- 使用最适合的最小宏类别。
- 保留卫生性、跨度、泛型、可见性和 edition 兼容性。
- 使用符合调用方实际用法的测试,覆盖成功展开和被拒绝的语法。
- 在支持的配置下通过格式检查、check、测试和 Clippy。
上游来源
数据隐私
此技能不会收集、存储或传输用户数据。生成的代码可能会嵌入输入字面量,因此在发布产物前,请检查展开结果中是否包含机密。