关于 rust-best-practices
rust-best-practices 是用于编写和审查 Rust 代码的参考 Skill,依据 Apollo GraphQL 的 Rust 最佳实践手册,涵盖惯用法、错误处理、性能、测试、类型与文档。
主要功能
- 01所有权与借用建议
- 02错误处理规范
- 03性能与 lint 建议
- 04测试建议
- 05泛型与类型状态指南
- 06文档编写实践
适用场景
- 01按 Rust 惯用法审查代码
- 02选择错误处理方式
- 03检查性能与 Clippy 问题
- 04规划测试和 API 文档
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ apollographql/ skills --skill rust-best-practices安装后在 Claude Code 中输入/rust-best-practices确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/chapter_01.mdchapter_02.mdchapter_03.mdchapter_04.mdchapter_05.mdchapter_06.mdchapter_07.mdchapter_08.mdchapter_09.md详细介绍
Rust 最佳实践
编写或审查 Rust 代码时,请遵循以下指南。内容基于 Apollo GraphQL 的 Rust 最佳实践手册。
最佳实践参考
审查前,请先熟悉 Apollo 的 Rust 最佳实践。在同一轮中并行阅读所有相关章节。提供反馈时请参考以下文件:
- 第 1 章 - 编码风格与惯用法:借用与克隆、Copy trait、Option/Result 处理、迭代器、注释、何时提取函数(重复与错误抽象)
- 第 2 章 - Clippy 与 Lint:Clippy 配置、重要 lint、工作区 lint 设置
- 第 3 章 - 性能思维:性能分析、避免不必要的克隆、栈与堆、零成本抽象
- 第 4 章 - 错误处理:Result 与 panic、thiserror 与 anyhow、错误层级
- 第 5 章 - 自动化测试:测试命名、每个测试一个断言、快照测试
- 第 6 章 - 泛型与分发:静态与动态分发、trait 对象
- 第 7 章 - 类型状态模式:编译时状态安全、何时使用
- 第 8 章 - 注释与文档:何时添加注释、文档注释、rustdoc
- 第 9 章 - 理解指针:线程安全、Send/Sync、指针类型
快速参考
借用与所有权
- 除非需要转移所有权,否则优先使用
&T而非.clone() - 函数参数中使用
&str而非String,使用&[T]而非Vec<T> - 小型
Copy类型(≤24 字节)可以按值传递 - 所有权不明确时使用
Cow<'_, T>
错误处理
- 对可能失败的操作返回
Result<T, E>;避免在生产代码中使用panic! - 在测试之外绝不使用
unwrap()/expect() - 库错误使用
thiserror,仅二进制程序使用anyhow - 错误传播时优先使用
?运算符,而非一连串 match
性能
- 始终使用
--release标志进行基准测试 - 运行
cargo clippy -- -D clippy::perf获取性能提示 - 避免在循环中克隆;对于 Copy 类型,使用
.iter()而非.into_iter() - 优先使用迭代器而非手动循环;避免调用中间的
.collect()
Lint
定期运行:cargo clippy --all-targets --all-features --locked -- -D warnings
需要关注的关键 lint:
redundant_clone- 不必要的克隆large_enum_variant- 过大的变体(可考虑装箱)needless_collect- 过早收集
使用 #[expect(clippy::lint)] 替代 #[allow(...)],并添加说明注释。
测试
- 使用描述性名称命名测试:
process_should_return_error_when_input_empty() - 尽可能让每个测试只包含一个断言
- 使用文档测试(
///)编写公共 API 示例 - 考虑使用
cargo insta对生成的输出进行快照测试
泛型与分发
- 对性能关键代码优先使用泛型(静态分发)
- 仅在需要异构集合时使用
dyn Trait - 在 API 边界处装箱,而非在内部装箱
类型状态模式
在类型系统中编码有效状态,以便在编译时捕获无效操作:
struct Connection<State> { /* ... */ _state: PhantomData<State> }
struct Disconnected;
struct Connected;
impl Connection<Connected> {
fn send(&self, data: &[u8]) { /* only connected can send */ }
}
文档
//注释解释“为什么”(安全性、变通方案、设计依据)///文档注释解释公共 API 的“是什么”和“如何使用”- 每个
TODO都需要关联的问题:// TODO(#42): ... - 为库启用
#![deny(missing_docs)]
评论
支持 Markdown