如何编写文档
好的文档不是天生的。有相互矛盾的目标使得编写好的文档变得困难。它需要对主题的专业知识,但也需要从初学者的角度进行写作。因此,文档通常会忽略实现细节,或者让读者留下未解答的问题。
Rust 文档有一些原则可以帮助任何人在文档库的过程中进行指导,以便每个人都有充分的机会使用代码。
本章不仅介绍如何编写文档,还专门介绍如何编写**好的**文档。清晰明了、尽可能完整非常重要。经验法则是:为你的板条箱编写的文档越多越好。如果一个项目是公开的,那么它就应该有文档。
入门
文档化一个板条箱应该从首页文档开始。例如,hashbrown
板条箱级别的文档总结了板条箱的作用,提供了解释技术细节的链接,并解释了为什么要使用该板条箱。
在介绍板条箱之后,首页应该提供一个示例,说明如何在现实世界中使用该板条箱。坚持使用库在示例中的作用,但不要使用捷径,以便那些可能复制粘贴示例来入门的用户受益。
futures
使用内联注释逐行解释使用 Future
的复杂性,因为一个人第一次接触 rust 的 Future
可能就是这个示例。
backtrace
文档逐步介绍了整个过程,解释了对 Cargo.toml
文件所做的更改,将命令行参数传递给编译器,并展示了 backtrace 在实际应用中的一个快速示例。
最后,首页最终可以成为一个关于如何使用板条箱的综合参考,例如 regex
。在这个首页中,概述了所有要求,展示了边缘情况,并提供了实际示例。首页继续展示如何使用正则表达式,然后以板条箱功能结束。
不要担心将你的板条箱(它才刚刚开始)与其他更成熟的板条箱进行比较。为了使文档更加完善,可以从增量开始,添加介绍、示例和功能。罗马不是一天建成的!
lib.rs
中的第一行将构成首页,它们使用与其他 rustdoc 不同的约定。行应该以 //!
开头,表示模块级或板条箱级文档。以下是一个快速示例,说明了区别
#![allow(unused)] fn main() { //! Fast and easy queue abstraction. //! //! Provides an abstraction over a queue. When the abstraction is used //! there are these advantages: //! - Fast //! - [`Easy`] //! //! [`Easy`]: http://thatwaseasy.example.com /// This module makes it easy. pub mod easy { /// Use the abstraction function to do this specific thing. pub fn abstraction() {} } }
理想情况下,这第一行文档是一个没有高度技术细节的句子,但对该板条箱在 rust 生态系统中的位置进行了很好的描述。用户在阅读完这一行后应该知道该板条箱是否满足他们的用例。
文档化组件
无论是模块、结构体、函数还是宏:所有代码的公共 API 都应该有文档。很少有人会抱怨文档太多!
建议每个项目的文档遵循以下基本结构
[short sentence explaining what it is]
[more detailed explanation]
[at least one code example that users can copy/paste to try it]
[even more advanced explanations if necessary]
在编写文档时,这个基本结构应该很容易遵循;虽然你可能认为代码示例是微不足道的,但示例非常重要,因为它们可以帮助用户理解一个项目是什么,如何使用它以及它存在的目的。
让我们从 标准库 中举一个例子,看看 std::env::args()
函数
Returns the arguments which this program was started with (normally passed
via the command line).
The first element is traditionally the path of the executable, but it can be
set to arbitrary text, and may not even exist. This means this property should
not be relied upon for security purposes.
On Unix systems shell usually expands unquoted arguments with glob patterns
(such as `*` and `?`). On Windows this is not done, and such arguments are
passed as-is.
# Panics
The returned iterator will panic during iteration if any argument to the
process is not valid unicode. If this is not desired,
use the [`args_os`] function instead.
# Examples
```
use std::env;
// Prints each argument on a separate line
for argument in env::args() {
println!("{argument}");
}
```
[`args_os`]: ./fn.args_os.html
第一个空行之前的任何内容都将被重复使用来描述搜索和模块概述中的组件。例如,上面的 std::env::args()
函数将在 std::env
模块文档中显示。保持摘要为一行是一个好习惯:简洁的写作是良好文档的目标。
由于类型系统在定义函数传递和返回的类型方面做得很好,因此在文档中明确写出它没有好处,尤其是在 rustdoc
为函数签名中的所有类型添加了超链接的情况下。
在上面的示例中,"Panics" 部分解释了代码何时可能突然退出,这可以帮助读者避免出现 panic。建议在代码中可以到达已知边缘情况时,始终添加 panic 部分。
如你所见,它遵循上面详细介绍的结构:它首先用一个简短的句子解释函数的作用,然后提供更多信息,最后提供一个代码示例。
Markdown
rustdoc
使用 CommonMark Markdown 规范。你可能想看看他们的网站,了解一下有哪些可能性
除了标准的 CommonMark 语法之外,rustdoc
还支持几个扩展
删除线
文本可以通过在文本两侧用一个或两个波浪号包裹来渲染为中间有一条水平线的文本
An example of ~~strikethrough text~~. You can also use ~single tildes~.
这个示例将渲染为
一个
删除线文本的示例。你也可以使用单个波浪号。
这遵循 GitHub 删除线扩展。
脚注
脚注在文本中生成一个小的编号链接,单击该链接会将读者带到项目底部的脚注文本。脚注标签的写法类似于链接引用,前面有一个插入符号。脚注文本的写法类似于链接引用定义,文本紧跟在标签之后。示例
This is an example of a footnote[^note].
[^note]: This text is the contents of the footnote, which will be rendered
towards the bottom.
这个示例将渲染为
这是一个脚注的示例1。
1这段文本是脚注的内容,它将在底部渲染。
脚注会根据脚注的编写顺序自动编号。
表格
表格可以使用管道和破折号来绘制表格的行和列。这些将被转换为与形状匹配的 HTML 表格。示例
| Header1 | Header2 |
|---------|---------|
| abc | def |
这个示例将渲染为类似于以下内容
Header1 Header2 abc def
有关支持的精确语法的更多详细信息,请参阅 GitHub 表格扩展 的规范。
任务列表
任务列表可以用作已完成项目的清单。示例
- [x] Complete task
- [ ] Incomplete task
这将渲染为
- 完成的任务
- 未完成的任务
有关更多详细信息,请参阅 任务列表扩展 的规范。
智能标点符号
某些 ASCII 标点符号序列将自动转换为花哨的 Unicode 字符
ASCII 序列 | Unicode |
---|---|
-- | – |
--- | — |
... | … |
" | “ 或 ”,取决于上下文 |
' | ‘ 或 ’,取决于上下文 |
因此,无需手动输入这些 Unicode 字符!
添加警告块
如果你想让警告或类似的注释在文档中突出显示,你可以像这样包裹它
/// documentation
///
/// <div class="warning">A big warning!</div>
///
/// more documentation
请注意,如果你想将 markdown 放入 HTML 标签中并将其解释为 markdown,则需要在 HTML 标签和 markdown 内容之间留出一行空行。例如,如果你想使用链接
/// documentation
///
/// <div class="warning">
///
/// Go to [this link](https://www.rust-lang.net.cn)!
///
/// </div>
///
/// more documentation