如何编写文档

良好的文档并非自然而然。编写好的文档存在相互矛盾的目标,这使得编写过程变得困难。它需要对主题的专业知识,同时也要从新手的角度进行写作。因此,文档通常会忽略实现细节,或者让读者留下未解答的问题。

Rust 文档有一些原则可以帮助任何人完成库的文档编写过程,以便每个人都有充分的机会使用代码。

本章不仅介绍如何编写文档,还专门介绍如何编写好的文档。尽可能清晰和完整地表达是很重要的。作为经验法则:为你的 crate 编写的文档越多越好。如果一个项是公开的,那么它就应该有文档。

入门

crate 的文档应该从首页文档开始。例如,hashbrown crate 级别的文档总结了 crate 的作用,提供了指向技术细节解释的链接,并解释了为什么要使用该 crate。

在介绍完 crate 后,重要的是首页要给出一个如何在真实环境中使用的例子。在例子中坚持库的作用,但不要使用快捷方式,以方便可能复制粘贴例子来入门的用户。

futures 使用内联注释逐行解释使用 Future 的复杂性,因为一个人第一次接触 rust 的 Future 可能就是这个例子。

backtrace 文档逐步介绍了整个过程,解释了对 Cargo.toml 文件所做的更改,向编译器传递命令行参数,并展示了一个在实际应用中使用回溯的快速示例。

最后,首页最终可以成为如何使用 crate 的全面参考,例如 regex。在这个首页中,概述了所有要求,显示了边缘情况,并提供了实际示例。首页继续展示如何使用正则表达式,最后以 crate 的特性结束。

不要担心将你刚开始的 crate 与其他更成熟的 crate 进行比较。为了使文档更加完善,请逐步开始,并加入简介、示例和特性。罗马不是一天建成的!

lib.rs 中的第一行将组成首页,并且它们使用与其余 rustdoc 不同的约定。行应该以 //! 开头,这表示模块级或 crate 级文档。这是一个快速示例,说明了差异

#![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() {}

}
}

理想情况下,文档的第一句话应该不包含高深的技术细节,但要很好地描述此 crate 在 rust 生态系统中的位置。用户在阅读完这句话后应该知道此 crate 是否满足他们的用例。

记录组件

无论是模块、结构体、函数还是宏:所有代码的公共 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     |

此示例将类似于此呈现

标题1标题2
abcdef

有关支持的确切语法的更多详细信息,请参见 GitHub 表格扩展 的规范。

任务列表

任务列表可以用作已完成项目的清单。例子

- [x] Complete task
- [ ] Incomplete task

这将呈现为

  • 已完成的任务
  • 未完成的任务

有关更多详细信息,请参见 任务列表扩展 的规范。

智能标点

一些 ASCII 标点符号序列将自动转换为精美的 Unicode 字符

ASCII 序列Unicode
--
---
...
"“ 或 ”,取决于上下文
'‘ 或 ’,取决于上下文

因此,无需手动输入这些 Unicode 字符!

添加警告块

如果想让警告或类似的注释在文档中突出显示,可以像这样包装它

/// documentation
///
/// <div class="warning">A big warning!</div>
///
/// more documentation

请注意,如果你想在 HTML 标签中放入 markdown 并将其解释为 markdown,则需要在 HTML 标签和 markdown 内容之间留一个空行。例如,如果你想使用链接

/// documentation
///
/// <div class="warning">
///
/// Go to [this link](https://rust-lang.net.cn)!
///
/// </div>
///
/// more documentation