Skip to content

Commit 6c4abf8

Browse files
committed
feat(skills): add m16-documentation skill for Rust documentation guidelines
1 parent 75eb330 commit 6c4abf8

1 file changed

Lines changed: 397 additions & 0 deletions

File tree

skills/m16-documentation/SKILL.md

Lines changed: 397 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,397 @@
1+
---
2+
name: m16-documentation
3+
description: "Use for writing Rust documentation comments. Keywords: 注释, comment, 文档, document, 添加注释, 写注释, add comment, doc comment, rustdoc"
4+
source: https://rust-coding-guidelines.github.io/rust-coding-guidelines-zh/
5+
user-invocable: false
6+
---
7+
8+
# Rust 文档注释规范
9+
10+
## 快速参考
11+
12+
| 类型 | 符号 | 用途 | 必需性 |
13+
|------|------|------|--------|
14+
| 模块文档 | `//!` | crate 根、模块顶部 | 推荐 |
15+
| 项目文档 | `///` | 公开 API | **必需** |
16+
| 实现注释 | `//` | 复杂逻辑 | 按需 |
17+
18+
## 核心规则
19+
20+
### 1. 公开 API 必须文档化
21+
22+
所有 `pub` 项目都需要 `///` 文档注释:
23+
24+
```rust
25+
// ❌ 错误
26+
pub fn process(data: &str) -> Result<()> { ... }
27+
28+
// ✅ 正确
29+
/// 处理输入数据并执行转换。
30+
///
31+
/// # Errors
32+
///
33+
/// 数据格式无效时返回错误。
34+
pub fn process(data: &str) -> Result<()> { ... }
35+
```
36+
37+
### 2. 文档注释结构模板
38+
39+
```rust
40+
/// 简短描述(一行,动词开头,以句号结尾)。
41+
///
42+
/// 详细描述段落(可选)。
43+
/// 可以包含多行,解释功能、用途和注意事项。
44+
///
45+
/// # Arguments
46+
///
47+
/// * `param` - 参数说明
48+
///
49+
/// # Returns
50+
///
51+
/// 返回值说明。
52+
///
53+
/// # Errors
54+
///
55+
/// 错误情况说明(Result 返回类型必需)。
56+
///
57+
/// # Example
58+
///
59+
/// ```
60+
/// use crate::module::Item;
61+
/// let item = Item::new();
62+
/// ```
63+
///
64+
/// # Panics
65+
///
66+
/// panic 条件(可能 panic 时必需)。
67+
///
68+
/// # Safety
69+
///
70+
/// unsafe 代码的安全保证(unsafe 函数必需)。
71+
```
72+
73+
### 3. 模块文档模板
74+
75+
```rust
76+
//! # 模块名称
77+
//!
78+
//! 一句话描述模块功能。
79+
//!
80+
//! ## 功能特性
81+
//!
82+
//! - 特性 1:说明
83+
//! - 特性 2:说明
84+
//!
85+
//! ## 模块结构
86+
//!
87+
//! - [`StructName`]: 结构说明
88+
//! - [`function_name`]: 函数说明
89+
```
90+
91+
### 4. 结构体文档模板
92+
93+
```rust
94+
/// 结构体的简短描述。
95+
///
96+
/// 详细说明用途和使用场景。
97+
///
98+
/// # Example
99+
///
100+
/// ```
101+
/// let item = Item::new();
102+
/// ```
103+
///
104+
/// # Cloning
105+
///
106+
/// (如适用)说明克隆行为和开销。
107+
///
108+
/// # Thread Safety
109+
///
110+
/// (如适用)说明线程安全性。
111+
pub struct Item {
112+
/// 字段说明(简短即可)。
113+
pub field: String,
114+
}
115+
```
116+
117+
## 章节规则
118+
119+
### 必需章节
120+
121+
| 章节 | 使用条件 |
122+
|------|----------|
123+
| `# Arguments` | 函数有参数时 |
124+
| `# Returns` | 函数有返回值时 |
125+
| `# Errors` | 返回 `Result`|
126+
| `# Panics` | 可能 panic 时 |
127+
| `# Safety` | `unsafe` 函数时 |
128+
129+
### 可选章节
130+
131+
| 章节 | 使用场景 |
132+
|------|----------|
133+
| `# Example` | 公开 API 推荐 |
134+
| `# Cloning` | 实现了 `Clone` 且行为特殊 |
135+
| `# Thread Safety` | 并发相关 |
136+
| `# Performance` | 性能特征重要时 |
137+
| `# See Also` | 相关项目引用 |
138+
139+
## 实现注释原则
140+
141+
### 何时需要实现注释 (`//`)
142+
143+
1. **复杂逻辑**:非显而易见的算法
144+
2. **性能优化**:为何选择这种实现
145+
3. **边界情况**:特殊处理的条件
146+
4. **锁作用域**:解释作用域限制
147+
5. **TODO/FIXME**:待处理事项
148+
149+
```rust
150+
// 历史长度限制:保留最近 N 轮对话(2N 条消息)
151+
// 使用 split_off 高效截断,避免迭代器开销
152+
if history.len() > self.max_history * 2 {
153+
*history = history.split_off(history.len() - self.max_history * 2);
154+
}
155+
156+
// 添加用户消息到历史(使用独立作用域限制锁的生命周期)
157+
{
158+
let mut conv = self.inner.conversation.write().await;
159+
conv.add_user_message(session_id, prompt);
160+
}
161+
```
162+
163+
### 何时不需要实现注释
164+
165+
```rust
166+
// ❌ 冗余:代码已自解释
167+
let len = items.len(); // 获取长度
168+
169+
// ✅ 必要:解释原因
170+
// 使用 Arc 包装,支持高效的克隆和共享
171+
let shared = Arc::new(inner);
172+
```
173+
174+
## 注释写作规范
175+
176+
### 1. 解释 "为什么",不是 "是什么"
177+
178+
```rust
179+
// ❌ 差:重复代码含义
180+
// 遍历所有元素
181+
for item in items.iter() { ... }
182+
183+
// ✅ 好:解释意图和原因
184+
// 使用迭代器而非索引,避免边界检查开销
185+
for item in items.iter() { ... }
186+
```
187+
188+
### 2. 保持简洁
189+
190+
```rust
191+
// ❌ 冗长
192+
/// 这个函数用于处理用户的输入数据,它会首先验证数据的格式是否正确,
193+
/// 然后将数据转换成内部格式,最后保存到数据库中。
194+
195+
// ✅ 简洁
196+
/// 处理、验证并保存用户输入数据。
197+
```
198+
199+
### 3. 使用完整句子
200+
201+
```rust
202+
// ❌ 不完整
203+
/// returns the length
204+
205+
// ✅ 完整
206+
/// 返回集合中的元素数量。
207+
```
208+
209+
### 4. 中英文混用规则
210+
211+
- 中文注释:团队成员都用中文
212+
- 英文术语:保留原文(如 `Arc`, `Mutex`, `async`
213+
- 代码示例:变量名用英文,注释用中文
214+
215+
```rust
216+
/// 使用 `Arc<Mutex<T>>` 实现共享状态。
217+
///
218+
/// 内部使用 `Arc` 包装,支持跨线程克隆共享。
219+
```
220+
221+
## 示例代码规范
222+
223+
### 1. 示例代码格式
224+
225+
```rust
226+
/// # Example
227+
///
228+
/// ```
229+
/// use crate::module::Item;
230+
///
231+
/// let item = Item::new();
232+
/// let result = item.process("data");
233+
/// ```
234+
235+
// 使用 `# ` 隐藏辅助代码
236+
/// # Example
237+
///
238+
/// ```
239+
/// # use crate::module::Item;
240+
/// # let item = Item::new();
241+
/// let result = item.process("data");
242+
/// ```
243+
```
244+
245+
### 2. 示例代码标记
246+
247+
| 标记 | 用途 |
248+
|------|------|
249+
| ```` ``` ```` | 默认:编译并运行测试 |
250+
| ```` ```no_run ```` | 编译但不运行(IO 操作等) |
251+
| ```` ```ignore ```` | 不编译也不运行(不完整示例) |
252+
| ```` ```compile_fail ```` | 应该编译失败(错误示例) |
253+
254+
## 文档链接
255+
256+
### 1. 链接到其他项目
257+
258+
```rust
259+
/// 与 [`chat`](Self::chat) 类似,但支持流式输出。
260+
/// 参考 [`ConversationManager`] 了解会话管理。
261+
pub fn chat_stream(&self, ...) { ... }
262+
```
263+
264+
### 2. 链接语法
265+
266+
```rust
267+
[`Item`] // 同模块
268+
[`module::Item`] // 其他模块
269+
[`Item::method`] // 方法
270+
[`method`](Item::method) // 显式路径
271+
```
272+
273+
## 检查清单
274+
275+
### 写注释前检查
276+
277+
- [ ] 是否是公开 API?→ 必须有 `///` 文档
278+
- [ ] 是否返回 `Result`?→ 必须有 `# Errors`
279+
- [ ] 是否可能 panic?→ 必须有 `# Panics`
280+
- [ ] 是否是 unsafe?→ 必须有 `# Safety`
281+
- [ ] 是否有参数?→ 应该有 `# Arguments`
282+
- [ ] 是否有返回值?→ 应该有 `# Returns`
283+
284+
### 写注释时检查
285+
286+
- [ ] 第一行是否是简短描述?
287+
- [ ] 是否解释了 "为什么" 而非 "是什么"?
288+
- [ ] 示例代码是否可编译?
289+
- [ ] 注释是否与代码同步?
290+
291+
### 写注释后检查
292+
293+
```bash
294+
# 生成文档并检查警告
295+
cargo doc --no-deps
296+
297+
# 运行文档测试
298+
cargo test --doc
299+
300+
# 使用 clippy 检查文档问题
301+
cargo clippy -- -W clippy::doc_markdown
302+
```
303+
304+
## 常见错误
305+
306+
### 1. 缺少必需章节
307+
308+
```rust
309+
// ❌ 错误:返回 Result 但没有 # Errors
310+
pub fn load(path: &str) -> Result<Data> { ... }
311+
312+
// ✅ 正确
313+
/// 从文件加载数据。
314+
///
315+
/// # Errors
316+
///
317+
/// 文件不存在或格式无效时返回错误。
318+
pub fn load(path: &str) -> Result<Data> { ... }
319+
```
320+
321+
### 2. 示例代码不可编译
322+
323+
```rust
324+
// ❌ 错误:缺少导入
325+
/// # Example
326+
///
327+
/// ```
328+
/// let item = Item::new(); // 未定义 Item
329+
/// ```
330+
331+
// ✅ 正确
332+
/// # Example
333+
///
334+
/// ```
335+
/// use crate::module::Item;
336+
/// let item = Item::new();
337+
/// ```
338+
```
339+
340+
### 3. 注释与代码不同步
341+
342+
```rust
343+
// ❌ 错误:注释说返回 3,实际返回 4
344+
/// 返回前 3 个元素。
345+
fn top_three(items: &[i32]) -> &[i32] {
346+
&items[..4] // 实际返回 4 个
347+
}
348+
```
349+
350+
## 工具支持
351+
352+
```bash
353+
# 检查文档缺失
354+
cargo doc --open
355+
356+
# 运行文档测试
357+
cargo test --doc
358+
359+
# clippy 文档检查
360+
cargo clippy -- -W clippy::missing_docs_in_private_items
361+
362+
# rustdoc 配置(lib.rs)
363+
#![warn(missing_docs)]
364+
```
365+
366+
## 自动检测缺失注释
367+
368+
### 使用 grep 检测
369+
370+
```bash
371+
# 检测缺少文档注释的 pub fn
372+
rg '^pub fn' -A 1 --type rust | rg '^[0-9]+:pub fn' -A 1 | rg -v '^[0-9]+-///'
373+
374+
# 检测缺少文档注释的 pub struct
375+
rg '^pub struct' -A 1 --type rust | rg '^[0-9]+:pub struct' -A 1 | rg -v '^[0-9]+-///'
376+
```
377+
378+
### 使用 cargo missing_docs
379+
380+
```bash
381+
# 安装
382+
cargo install cargo-missing-docs
383+
384+
# 运行检查
385+
cargo missing-docs
386+
```
387+
388+
### CI 配置
389+
390+
```yaml
391+
# .github/workflows/docs.yml
392+
- name: Check documentation
393+
run: |
394+
cargo doc --no-deps
395+
cargo test --doc
396+
cargo clippy -- -W clippy::missing_docs_in_private_items
397+
```

0 commit comments

Comments
 (0)