什么是 rustdoc?

标准的 Rust 发行版,附带了一个名为rustdoc的工具。它的任务是为 Rust 项目,生成(示例/代码)文档。基本层面理解为,Rustdoc 将 一个 (crate root)箱子的根目录 或 Markdown 文件作为参数,并生成 HTML,CSS 和 JavaScript。

基本用法

试一试吧!让我们用 Cargo 创建一个新项目:

$ cargo new docs
$ cd docs

src/lib.rs,你会发现 Cargo 已经生成了一些示例代码。删除它并替换为:


# #![allow(unused_variables)]
#fn main() {
/// foo 是一个函数
fn foo() {}
#}

让我们用rustdoc对准我们的代码。为此,到达我们的 crate root 的路径上,调用它,如下所示:

$ rustdoc src/lib.rs

这将创建一个新目录,doc,里面有一个网站!在我们的例子中,主网页是doc/lib/index.html。如果你在网络浏览器中打开它,你会看到一个带有搜索栏的页面,顶部有“Crate lib”,没有内容。这有两个问题:

  • 首先,为什么我们的包名是“lib”?
  • 第二,为什么它没有任何内容?

第一个问题是由于,rustdoc想要给出帮助信息;如同rustc一样,它会假定我们的箱子名,就是箱子根目录的文件名。要解决这个问题,我们可以传入一个命令行标志:

$ rustdoc src/lib.rs --crate-name docs

现在,doc/docs/index.html将生成,页面显示“Crate docs”。

对于第二个问题,是因为我们的函数foo是不公开的;rustdoc默认仅为公开函数,生成文档。如果我们改变我们的代码...


# #![allow(unused_variables)]
#fn main() {
/// foo 是一个函数
pub fn foo() {}
#}

...然后重新运行rustdoc

$ rustdoc src/lib.rs --crate-name docs

我们将有一些生成的文档。打开doc/docs/index.html并检查出来!它应该显示一个链接foo函数页面,位于doc/docs/fn.foo.html。在那个页面上,你会看到“foo 是一个函数”,正是我们放在箱子的文档注释。

rustdoc 搭配 Cargo

Cargo 也有整合rustdoc使生成文档更容易。不是rustdoc命令,我们会使用:

$ cargo doc

在内部,会像这样调用rustdoc

$ rustdoc --crate-name docs srclib.rs -o <path>\docs\target\doc -L
dependency=<path>docs\target\debug\deps

cargo doc --verbose,能看到这个详细信息。

可以看到,内部命令为我们生成了正确的--crate-name,以及指向src/lib.rs,但那些其他参数呢?-o控制我们文档的output(输出目录)。不再是doc顶级目录,您会注意到 Cargo 把生成的文档放在target。这是 Cargo 项目中,生成文件的惯用场所。还有,一个-L标志,它帮助 rustdoc 找到您的代码所依赖的依赖项。如果我们的项目使用依赖项,我们也会获得它们的文档!

使用独立的 Markdown 文件

rustdoc也可以从独立的 Markdown 文件生成 HTML。让我们试一试:创建一个README.md,包含以下内容的文件:

# Docs

This is a project to test out `rustdoc`.

[Here is a link!](https://www.rust-lang.org)

## Subheading

```rust
fn foo() -> i32 {
    1 + 1
}
```

调用rustdoc

$ rustdoc README.md

你会找到一个 HTML 文件docs/doc/README.html,源自 Markdown 内容。

不幸的是,Cargo 目前无法理解独立的 Markdown 文件。

摘要

这涵盖了最简单的rustdoc用例。本书的其余部分,将解释rustdoc所有的选项,以及如何使用它们。

命令行参数

这是您可以传递给rustdoc的参数列表:

-h/--help:帮助

使用此标志如下:

$ rustdoc -h
$ rustdoc --help

这将显示rustdoc的内置帮助,主要由能用的命令行标志列表组成。

会有一些rustdoc的标志参数不稳定;此页仅显示稳定的选项,--help则会显示全部。

-V/--version:版本信息

使用此标志如下:

$ rustdoc -V
$ rustdoc --version

这将显示rustdoc的版本,其外观如下:

rustdoc 1.17.0 (56124baa9 2017-04-24)

-v/--verbose:更详细的输出

使用此标志如下:

$ rustdoc -v src/lib.rs
$ rustdoc --verbose src/lib.rs

这将启用“详细模式”,这意味着更多信息将写入标准输出。所写的内容取决于您传入的其他标志。例如,使用--version

$ rustdoc --verbose --version
rustdoc 1.17.0 (56124baa9 2017-04-24)
binary: rustdoc
commit-hash: hash
commit-date: date
host: host-triple
release: 1.17.0
LLVM version: 3.9

-r/--input-format:输入格式

此标志当前被忽略;想法是rustdoc将支持各种输入格式,您可以通过这个标志来指定它们。

RustDoc 只支持 Rust 源代码和 markdown 输入格式。如果文件以.md.markdownrustdoc将其视为 markdown 文件。否则,它假定输入文件是 Rust 的。

-w/--output-format:输出格式

此标志当前被忽略;其想法是rustdoc将支持各种输出格式,您可以通过此标志指定它们。

RustDoc 只支持 HTML 输出,所以这个标志在今天来说是多余的。

-o/--output:输出路径

使用此标志如下:

$ rustdoc src/lib.rs -o target\\doc
$ rustdoc src/lib.rs --output target\\doc

默认情况下,rustdoc的输出显示在当前工作目录中的doc目录。使用这个标志,它将把所有输出放到您指定的目录中。

--crate-name:控制箱子的名称

使用此标志如下:

$ rustdoc src/lib.rs --crate-name mycrate

默认情况下,rustdoc假设箱子的名称与.rs文件名一样。--crate-name允许您用您选择的任何名称覆盖这个假设。

-L/--library-path:查找依赖项的位置

使用此标志如下:

$ rustdoc src/lib.rs -L target/debug/deps
$ rustdoc src/lib.rs --library-path target/debug/deps

如果你的箱子有依赖性,rustdoc需要知道在哪里找到他们。传递--library-path参数,让rustdoc可以查找这些依赖项的位置列表。

此标志接受任意数量的目录作为参数,并在搜索时,使用所有文档。

--cfg:传递配置标志

使用此标志如下:

$ rustdoc src/lib.rs --cfg feature="foo"

此标志接受的值与rustc --cfg一样,也可以用来配置编译。上面的示例使用feature,但任何的cfg值都是可以接受的。

--extern:指定依赖项的位置

使用此标志如下:

$ rustdoc src/lib.rs --extern lazy-static=/path/to/lazy-static

类似--library-path--extern是关于指定依赖项的位置。--library-path提供要搜索的目录,--extern相反,您可以确切地指定依赖项位于何处。

-C/--codegen:将 codegen 选项传递给 rustc

使用此标志如下:

$ rustdoc src/lib.rs -C target_feature=+avx
$ rustdoc src/lib.rs --codegen target_feature=+avx

$ rustdoc --test src/lib.rs -C target_feature=+avx
$ rustdoc --test src/lib.rs --codegen target_feature=+avx

$ rustdoc --test README.md -C target_feature=+avx
$ rustdoc --test README.md --codegen target_feature=+avx

当 RustDoc 生成文档、查找文档测试或执行文档测试时,它需要编译一些 Rust 代码,至少是部分编译。此标志允许您告诉 RustDoc 在运行这些编译时,向 RustC 提供一些额外的 codegen 选项。大多数情况下,这些选项不会影响常规文档运行,但如果某些内容会依赖要启用的目标功能(target feature),或者文档测试需要使用一些其他选项,这时,这个标志就能让您影响这些内容。

此标志的参数与 rustc 上的-C标志一样。运行rustc -C help获取完整的列表。

--passes:添加更多 RustDoc psses(通行证)

使用此标志如下:

$ rustdoc --passes list
$ rustdoc src/lib.rs --passes strip-priv-imports

“list”参数将打印一个可能的“rustdoc passes”列表,除默认值外,其他参数则是功能与其名。

有关通行证的详细信息,请参见关于它们的章节.

另请参见--no-defaults.

--no-defaults:不运行默认通行证

使用此标志如下:

$ rustdoc src/lib.rs --no-defaults

默认情况下,rustdoc在代码上运行多个通行证。此标志就是删除这些默认值的,让你自行重新传递--passes,以准确指定所需的通行证。

有关通行证的详细信息,请参见关于它们的章节.

另请参见--passes.

--test:将代码示例作为测试运行

使用此标志如下:

$ rustdoc src/lib.rs --test

此标志将运行代码示例作为测试。有关更多信息,请参阅文档测试章节

另请参见--test-args.

--test-args:传递选项给测试运行程序

使用此标志如下:

$ rustdoc src/lib.rs --test --test-args ignored

此标志将在运行文档测试时,将选项传递给测试运行程序。有关更多信息,请参阅文档测试章节

另请参见--test.

--target:为指定的三元目标,生成文档

使用此标志如下:

$ rustdoc src/lib.rs --target x86_64-pc-windows-gnu

类似于rustc--target标志,生成指定三元目标的文档。

所有跨平台编译代码的常见注意事项都适用。

--markdown-css:渲染 markdown 时,包含更多 CSS 文件

使用此标志如下:

$ rustdoc README.md --markdown-css foo.css

渲染 markdown 文件时,这将在生成 HTML 的<head>元素内,创建一个<link>元素。例如,上面的调用会生成,

<link rel="stylesheet" type="text/css" href="foo.css" />

添加到 HTML。

渲染 Rust 文件时,此标志将被忽略。

--html-in-header:在 中 包含更多 HTML

使用此标志如下:

$ rustdoc src/lib.rs --html-in-header header.html
$ rustdoc README.md --html-in-header header.html

此标志获取文件列表,并将其插入到渲染文档的<head>

--html-before-content:在 content 之前,包含更多 HTML

使用此标志如下:

$ rustdoc src/lib.rs --html-before-content extra.html
$ rustdoc README.md --html-before-content extra.html

此标志获取文件列表,并将其插入到渲染文档的<body>标记元素,但排在其他 content(内容) 之前。

--html-after-content:在 content 之后,包含更多 HTML

使用此标志如下:

$ rustdoc src/lib.rs --html-after-content extra.html
$ rustdoc README.md --html-after-content extra.html

此标志获取文件列表,并将其插入到渲染文档的</body>标记元素,但排在其他 content 之后。

--markdown-playground-url:控制游乐场的位置

使用此标志如下:

$ rustdoc README.md --markdown-playground-url https://play.rust-lang.org/

在渲染 markdown 文件时,此标志提供 Rust Playground 的基 URL,用于生成Run按钮。

--markdown-no-toc:不生成文件目录超链接

使用此标志如下:

$ rustdoc README.md --markdown-no-toc

从 markdown 文件生成文档时,默认情况下,rustdoc将生成目录。此标志禁止此操作,不会生成 TOC(目录超链接)。

-e/--extend-css:扩展 RustDoc 的 CSS

使用此标志如下:

$ rustdoc src/lib.rs -e extra.css
$ rustdoc src/lib.rs --extend-css extra.css

使用此标志,您传递文件的内容,将添加到 RustDoc theme.css文件的下面。

当此标志稳定时,theme.css的内容会不在了,所以小心点!更新可能会破坏你的主题扩展。

--sysroot:重写系统根目录

使用此标志如下:

$ rustdoc src/lib.rs --sysroot /path/to/sysroot

类似rustc --sysroot,这允许您在编译代码时,更改rustdoc使用的 sysroot。

--edition:控制文档和文档测试的版本(edition)

使用此标志如下:

$ rustdoc src/lib.rs --edition 2018
$ rustdoc --test src/lib.rs --edition 2018

此标志允许 RustDoc 将您的 Rust 代码视为给定版本。它也将用给定的版本编译文档测试。与rustc一样,rustdoc使用的默认版本是2015(第一版)。

#[doc]属性

#[doc]属性可以让你控制rustdoc各个方面的工作。

#[doc]最基本的功能就是处理实际的文档文本。///,就是#[doc]的语法糖。这意味着,这两个是相同的:

/// This is a doc comment.
#[doc = " This is a doc comment."]

(注意属性版本中,字符串的前空格。)

在多数情况下,///比起#[doc]更容易使用。后者更容易使用的一种情况,是在宏中生成文档;collapse-docs通行证参数会把多个#[doc]属性,结合到单个 doc 注释中,让您生成如下代码:

#[doc = "This is"]
#[doc = " a "]
#[doc = "doc comment"]

能感觉更加灵活。注意这会生成:

#[doc = "This is\n a \ndoc comment"]

但鉴于文档是通过 Markdown 呈现的,它将删除这些换行符。

doc属性版本会有更多的选项!不是涉及输出文本的,而是有关输出描述的各个方面。我们把它们分为以下两种:箱子级别有用的属性,以及项目级别有用的属性。

在箱子级别

这些选项控制文档,在宏观层面的外观。

html_favicon_url

doc属性的这种形式,可让您控制文档的图标。

#![doc(html_favicon_url = "https://example.com/favicon.ico")]

这会将<link rel="shortcut icon" href="{}">放入你的文档(HTML),{}就是你的字符串。

如果您不使用此属性,则不会有图标。

html_logo_url

doc属性的这种形式,允许您控制文档左上角的徽标。

#![doc(html_logo_url = "https://example.com/logo.jpg")]

这将提出<a href='index.html'><img src='{}' alt='logo' width='100'></a>进入你的文档,{}就是你的字符串。

如果您不使用此属性,则不会有徽标。

html_playground_url

doc属性的这种形式,可以控制文档示例中的“Run”按钮,发出请求的位置。

#![doc(html_playground_url = "https://playground.example.com/")]

现在,当您按“Run”时,该按钮将向此域名发出请求。

如果您不使用此属性,则不会有 Run 按钮。

issue_tracker_base_url

doc属性的这种形式,大多只对标准库有用;当一个功能不稳定时,必须提供跟踪该功能的问题编号。rustdoc使用编号,加上此处给出的基本 URL,链接到跟踪问题。

#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]

html_root_url

#[doc(html_root_url = "…")]属性的值,表示生成指向外部箱子的 URL 链接。当 rustdoc 需要生成指向一个外部箱子的项的链接时,它将首先检查外部箱子,是否已在本地磁盘上记录,如果是,则直接链接到它。如果不是,它将使用--extern-html-root-url命令行标志给出的 URL(如果可用)。如果也没有,那么它将使用 extern crate 中的html_root_url值(如果可用)。如果还不可用,则不会链接 extern 项。

#![doc(html_root_url = "https://docs.rs/serde/1.0")]

html_no_source

默认情况下,rustdoc将包含您的程序的源代码,以及在文档中的链接。但如果你包括这个:

#![doc(html_no_source)]

就不默认。

test(no_crate_inject)

默认情况下,rustdoc会自动添加一行extern crate my_crate;进入每个 doctest(文档测试)。但如果你包括这个:

#![doc(test(no_crate_inject))]

它不会。

test(attr(...))

doc属性的这种形式,允许您向所有 doctests 添加任意属性。例如,如果您希望您的 doctests 在产生任何警告时失败,您可以添加以下内容:

#![doc(test(attr(deny(warnings))))]

项目级别

#[doc]属性的这些形式,用于单个项目,以控制它们的文档化方式。

#[doc(no_inline)]/#[doc(inline)]

这些属性用在use声明语句,和控制文档出现的位置。例如,考虑这个 Rust 代码:

pub use bar::Bar;

/// bar docs
pub mod bar {
    /// the docs for Bar
    pub struct Bar;
}

该文档将生成“Re-exports”部分,并给出pub use bar::Bar;,那这个Bar会是它自身页面的链接。

但如果我们像这样,改变了use行:

#[doc(inline)]
pub use bar::Bar;

Bar就变成,出现在Structs部分,Bar就像是在顶层定义的,而不是pub use形式。

让我们改变我们原来的例子,把bar模块变为私有:

pub use bar::Bar;

/// bar docs
mod bar {
    /// the docs for Bar
    pub struct Bar;
}

在这里,因为bar不公开,Bar就不会有自己的页面,所以没有地方可以链接。rustdoc将内联(inline)这些定义,因此我们最终的结果与上面#[doc(inline)]一样;BarStructs部分,好像它是在顶层定义的。如果,我们换成no_inline

#[doc(no_inline)]
pub use bar::Bar;

/// bar docs
mod bar {
    /// the docs for Bar
    pub struct Bar;
}

现在变成,有一个Re-exports部分,但Bar不会链接到任何地方。

一个特例:在 Rust 2018 及以后,如果你pub use你的一个依赖,除非你添加#[doc(inline)],否则rustdoc不会急切地将其作为模块内联。

#[doc(hidden)]

任何带#[doc(hidden)]注释的项不会出现在文档中,除非strip-hidden通行证参数被删除。

#[doc(primitive)]

由于原始类型是在编译器中定义的,因此无法附加文档属性。标准库会用此属性提供的方法,生成原始类型的文档。

文档测试

rustdoc支持执行文档示例,作为测试。这可以确保您的测试是最新的和有效的。

基本的想法是这样的:

/// # Examples
///
/// ```
/// let x = 5;
/// ```

三个反引号开始和结束的代码块。如果这是在一个名为foo.rs的文件中,运行rustdoc --test foo.rs将提取此示例,然后将其作为测试运行。

请注意,默认情况下,如果没有为代码块设置语言,rustdoc假设它是Rust码。所以,以下内容:

```rust
let x = 5;
```

严格等同于:

```
let x = 5;
```

虽然有些微妙!但请继续。

通过或未通过一个 doctest(文档测试)

与常规单元测试一样,如果编译和运行没有恐慌,常规 doctests 被认为是“通过”。因此,如果你想证明一些计算给出一定的结果,那么assert!宏家族的工作与常规 Rust 代码相同:


# #![allow(unused_variables)]
#fn main() {
let foo = "foo";

assert_eq!(foo, "foo");
#}

这样,如果计算返回不同的东西,代码恐慌,并且 doctest 失败。

预处理示例

在上面的例子中,你会注意到一些奇怪的事情:没有main函数!若是强迫你在每个示例中,都要写main,无论这举动多小,都不太懒人化。所以rustdoc会在运行之前稍微处理您的示例。这就是 rustdoc 预处理示例的完整算法:

  1. 插入些常见allow属性,包括unused_variablesunused_assignmentsunused_mutunused_attributes,和dead_code。小例子经常触发这些 lint。
  2. 使用#![doc(test(attr(...)))]指定的任何属性,会被添加。
  3. 任何#![foo]前缀属性保留为 箱子属性。
  4. 如果示例不包含extern crate,和没有指定#![doc(test(no_crate_inject))],那就插入extern crate <mycrate>;(注意#[macro_use]的缺乏)。
  5. 最后,如果示例不包含fn main,文本的其余部分包含在fn main() { your_code }

有关规则 4 中警告的更多信息,请参阅下面的“宏文档”。

隐藏示例的部分内容

有时,您需要一些设置代码,或其他会分散您示例,但对有效测试非常重要的的内容。考虑一个如下所示的示例块:

/// /// Some documentation.
/// # fn foo() {} // this function will be hidden
/// println!("Hello, World!");

它将呈现如下:


# #![allow(unused_variables)]
#fn main() {
/// Some documentation.
# fn foo() {}
println!("Hello, World!");
#}

是的,这是正确的:你可以添加以#开头的行,它们将从输出中隐藏,但在编译代码时将被使用。你可以利用这个优势。设想下,当文档注释需要应用于某种函数,所以如果我只想向您展示文档注释,我需要在它下面添加一个小函数定义。同时,它只是满足编译器,所以隐藏它,会使示例更清晰。您可以使用此技术,详细解释更长的示例,同时仍保留文档的可测试性。

例如,假设我们想要文档化此代码:


# #![allow(unused_variables)]
#fn main() {
let x = 5;
let y = 6;
println!("{}", x + y);
#}

我们可能希望文档最终看起来像这样:

首先,我们设定x到 5:


# #![allow(unused_variables)]
#fn main() {
let x = 5;
# let y = 6;
# println!("{}", x + y);
#}

接下来,我们设置y到 6:


# #![allow(unused_variables)]
#fn main() {
# let x = 5;
let y = 6;
# println!("{}", x + y);
#}

最后,我们打印出的总和xy


# #![allow(unused_variables)]
#fn main() {
# let x = 5;
# let y = 6;
println!("{}", x + y);
#}

为了保持每个代码块可测试,我们希望每个块,都有整个程序,但我们不希望读者每次都看到每一行。这是我们在源代码中添加的内容:

First, we set `x` to five:

```
let x = 5;
# let y = 6;
# println!("{}", x + y);
```

Next, we set `y` to six:

```
# let x = 5;
let y = 6;
# println!("{}", x + y);
```

Finally, we print the sum of `x` and `y`:

```
# let x = 5;
# let y = 6;
println!("{}", x + y);
```

通过重复示例的所有部分,您可以确保您的示例仍然编译,同时仅显示与您的解释部分相关的部分。

通过使用两个连续的##哈希值,可以防止隐藏。这只需要用第一个完成#否则会导致隐藏。如果我们有一个像下面这样的字符串文字,它有一行是以一个#开头的字符串:


# #![allow(unused_variables)]
#fn main() {
let s = "foo
## bar # baz";
#}

我们可以通过转义头个#来文档化它:

/// let s = "foo
/// ## bar # baz";

在文档测试中运用?

在编写示例时,包含完整的错误处理很少有用,因为它会添加大量的样板代码。相反,您可能需要以下内容:

/// ```
/// use std::io;
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
/// ```

问题是,?会返回一个Result<T, E>,而测试函数是不返回任何内容,因此这会给出不匹配的类型错误。

你可以通过手动添加一个main,它返回Result<T, E>,因为Result<T, E>实现Terminationtrait,自然解决了这个限制:

/// A doc test using ?
///
/// ```
/// use std::io;
///
/// fn main() -> io::Result<()> {
///     let mut input = String::new();
///     io::stdin().read_line(&mut input)?;
///     Ok(())
/// }
/// ```

再加上从上面的#部分,您可以得出一个解决方案,在读者看来它就是最初的想法,但可以与文档测试一起使用:

/// ```
/// use std::io;
/// # fn main() -> io::Result<()> {
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
/// # Ok(())
/// # }
/// ```

从 1.34.0 版开始,还可以省略fn main(),但必须消除错误类型的歧义:

/// ```
/// use std::io;
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
/// # Ok::<(), io::Error>(())
/// ```

?运算符要添加隐式转换,是一个不幸的结果。是因为类型不是唯一的,所以不这样的话,会导致类型推断失败。请注意,您必须写下(())序列,中间没有空格,以便 RustDoc 了解您需要一个隐式Result——返回函数。

从 1.37.0 版开始,这种简化也适用于Options,可以方便地测试,例如迭代器或校验算术,例如:

/// ```
/// let _ = &[].iter().next()?;
///# Some(())
/// ```

请注意,结果必须是Some(()),且必须一次。在这种情况下,不需要消除结果的歧义。

宏的文档

以下是一个宏的文档示例:

/// 除非表达式正确,不然就信息性恐慌
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate foo;
/// # fn main() {
/// panic_unless!(1 + 1 == 2, “Math is broken.”);
/// # }
/// ```
///
/// ```should_panic
/// # #[macro_use] extern crate foo;
/// # fn main() {
/// panic_unless!(true == false, “I’m broken.”);
/// # }
/// ```
#[macro_export]
macro_rules! panic_unless {
    ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
}
# fn main() {}

你会注意到三件事:

  • 1,我们需要增加我们自己的extern crate行,以便我们可以添加#[macro_use]属性。
  • 2,我们需要增加我们自己的main()以及(出于上述原因)。
  • 3,最后,明智地使用#注释掉这两件事,这样它们就不会出现在输出中。

属性

有一些注释对rustdoc正确测试代码的事情上有帮助:


# #![allow(unused_variables)]
#fn main() {
/// ```ignore
/// fn foo() {
/// ```
# fn foo() {}
#}

这个ignore指令告诉 Rust 忽略您的代码。大概是你不想要的(代码),因为它太普通了。相反,如果不是代码,考虑用text文本,或者使用#得到一个只显示你关心的部分的工作示例。


# #![allow(unused_variables)]
#fn main() {
/// ```should_panic
/// assert!(false);
/// ```
# fn foo() {}
#}

should_panic讲述rustdoc代码应该正确编译,但不能作为测试通过。

/// ```no_run
/// loop {
///     println!("Hello, world");
/// }
/// ```
# fn foo() {}

这个no_run属性将编译代码,但不运行它。这对“以下是如何检索网页”等示例很重要,您可能希望确保编译,但可能是在没有网络访问的测试环境中运行。

/// ```compile_fail
/// let x = 5;
/// x += 2; // shouldn't compile!
/// ```

compile_fail讲述rustdoc编译应该失败。如果它编译,那么测试将失败。但是,请注意,随着新特性的添加,在当前 Rust 标准版失败的代码,可能在将来的版本中工作。

/// 只在 2018 edition 运行.
///
/// ```edition2018
/// let result: Result<i32, ParseIntError> = try {
///     "1".parse::<i32>()?
///         + "2".parse::<i32>()?
///         + "3".parse::<i32>()?
/// };
/// ```

edition2018讲述rustdoc代码样本,应在 2018 版 Rust 下编译。同样,您可以指定edition2015以 2015 年版编制本规范。

语法参考

准确的代码块(包括边缘大小写)的语法可以在通用标记规范的用栅栏围起来的代码块章节找到。

RustDoc 也接受缩进代码块,作为栅栏代码块的替代:您可以将每行缩进四个或更多的空格,而不是用三个反勾号包围代码。

    let foo = "foo";
    assert_eq!(foo, "foo");

这些也记录在通用标记规范中,缩进代码块章节。

但是,最好使用栅栏代码块,而不是缩进代码块。不仅仅是栅栏代码块被认为是 Rust 代码的习惯,还因为缩进代码块没有办法使用诸如ignoreshould_panic

通行证/传递参(Passes)

Rustdoc 有一个名为“passes”的概念。这些是在生成最终输出之前,rustdoc文档的转变方式。

除了下面描述的 passes 之外,也可以看看这些标志的文档:

默认通行证

默认情况下,rustdoc 将运行一些传递参,即:

  • strip-hidden
  • strip-private
  • collapse-docs
  • unindent-comments

而,strip-private暗示strip-private-imports(剔除私有导入),所以有效地,默认情况下运行所有传递。

strip-hidden

这个传递参实现了#[doc(hidden)]属性。当此传递参运行时,它会检查每个项,若使用此属性进行注释,则会将其从rustdoc的输出中删除。

如果没有此传递参,这些项将保留在输出中。

unindent-comments

当你写这样的文档注释时:

/// This is a documentation comment.

///T之间有一个空格。该空格间距不是输出的一部分;但它更利于人类阅读,帮助我们将注释语法与注释文本分开。这个传递参就是移除那个空格。

确切的数量规则未指定,所以我们可以解决我们发现的问题。

没有此传递参,将保留确切的空格数。

collapse-docs

有了这个传递参,多个#[doc]属性会转换为单个文档字符串。

例如:

#[doc = "This is the first line."]
#[doc = "This is the second line."]

会折叠成单个文档字符串

This is the first line.
This is the second line.

strip-private

这将删除任何非-公共项的文档,例如:

/// These are private(私有) docs.
struct Private;

/// These are public(公共) docs.
pub struct Public;

此传递参删除了Private文档,因为他们不公开。

这个传递参,意味着strip-priv-imports

strip-priv-imports

这与strip-private一样的,但针对extern crateuse语句,而不是项。

不稳定的功能

Rustdoc 正在积极开发中,与 Rust 编译器一样,某些功能仅在夜间版本中可用。其中一些功能是新功能,需要进一步测试才能将它们发布到全世界,其中一些功能与 Rust 编译器中不稳定的功能相关联。这里的一些功能需要有匹配#![feature(...)]启用,而更全面的文档,记录在不稳定的书。文档有些部分会根据需要链接到那里。

译者:crate - 箱子;trait - 特质;

夜间(nightly)功能

以下功能只需要夜间构建即可运行。与此页面上的其他功能不同,这些功能不需要用命令行标志“打开”,或在箱子上写有#![feature(...)]属性。若是在稳定(stable)版本上使用(这些功能)时,会留一些后路模式,所以还是要小心!

compile-fail文档测试的错误编号

详见文档测试的章节,你可以为 doctest 添加一个compile_fail属性,表明测试应该无法通过编译。但是,在夜间,您可以选择添加错误编号,以声明 doctest 应该发出特定的错误编号:

```compile_fail,E0044
extern { fn some_func<T>(x: T); }
```

错误索引(error index)会使用它(E0044),确保样本正确地发出对应错误代码。但是,这些错误代码不能保证的唯一一件事是,这一段代码在版本之间没有问题,因此将来不太可能稳定。

尝试在 stable 版本上使用这些错误号,将导致代码示例被解释为纯文本。

按类型,链接到某项

按照RFC 1946的设计,当您将某项用作链接时,Rustdoc 可以解析项的路径。要解析这些类型名称,它通过声明或通过use,使用当前在范围内的项。对于模块,“活动范围”取决于文档是否写在模块外部(如mod内的///注释)或模块内部(文件或块内的//!注释)。对于所有其他项,它使用封闭模块的范围。

例如,在以下代码中:


# #![allow(unused_variables)]
#fn main() {
/// Does the thing.
pub fn do_the_thing(_: SomeType) {
    println!("Let's do the thing!");
}

/// Token you use to [`do_the_thing`].
pub struct SomeType;
#}

SomeType的文档有[`do_the_thing`]链接,会正确链接到fn do_the_thing页面。请注意,在这里,rustdoc 将为您插入链接目标,但手动编写目标也可以:


# #![allow(unused_variables)]
#fn main() {
pub mod some_module {
    /// Token you use to do the thing.
    pub struct SomeStruct;
}

/// Does the thing. 需要一个 [`SomeStruct`] for the thing to work.
///
/// [`SomeStruct`]: some_module::SomeStruct
pub fn do_the_thing(_: some_module::SomeStruct) {
    println!("Let's do the thing!");
}
#}

有关详细信息,请查看RFC,看看跟踪问题有关该功能的哪些部分可用的更多信息。

#[doc]属性扩展

下面功能通过扩展#[doc]属性来操作,因此可以被编译器捕获,并启用箱子中的#![feature(...)]属性。

记录,特定平台/功能的信息

由于 Rustdoc 记录箱子的方式,它创建的文档与特定目标 rustc 编译有关。(源代码)任何非特定的东西都会被丢弃,这是通过#[cfg]在编译过程的早期进行属性处理完成的。但是,Rustdoc 有一个技巧可以处理确定存在的特定平台代码。

因为 Rustdoc 不需要将 crate 完全编译为二进制文件,所以它会把函数体替换成loop {},防止不必要的处理。这意味着,将忽略函数中,要求为特定平台部分的任何代码。结合特殊属性,#[doc(cfg(...))],你可以告诉 Rustdoc 确切运行的平台,确保 doctests 只在适当的平台上运行。

#[doc(cfg(...))]属性具有另一个效果:当 Rustdoc 渲染该项的文档时,它将附有一个横幅(提示),说明该项仅在某些平台上可用。

对于 Rustdoc 来记录项,它需要查看它,无论它当前在哪个平台上运行。为了解决这个问题,Rustdoc 在你的箱子上运行时,会设置标志#[cfg(rustdoc)]。将此与项的给定目标平台(如:windows)相结合,可以在该平台上正常构建您的箱子以及任何地方构建文档的情况下,显示它。

例如,#[cfg(any(windows, rustdoc))]将在 Windows 上或在文档化过程中,保留项。然后,添加新属性#[doc(cfg(windows))]将告诉 Rustdoc,该项应该在 Windows 上使用。例如:


# #![allow(unused_variables)]
#![feature(doc_cfg)]

#fn main() {
/// Token struct that can only be used on Windows.
#[cfg(any(windows, rustdoc))]
#[doc(cfg(windows))]
pub struct WindowsToken;

/// Token struct that can only be used on Unix.
#[cfg(any(unix, rustdoc))]
#[doc(cfg(unix))]
pub struct UnixToken;
#}

在此示例中,Token 只会出现在各自的平台上,但它们都会出现在文档中。

#[doc(cfg(...))]被引入标准库使用,目前需要#![feature(doc_cfg)]功能守卫。有关更多信息,请参阅它在不稳定之书的章节它的跟踪问题

将您的 trait 添加到“Important Traits”对话框

Rustdoc 保存了一个列表,有一些 trait(特质),这些特质在实现时被认为是给定类型的“基础”。这些特质旨在成为其类型的主要接口,并且通常是其类型的唯一可用文档。因此,Rustdoc 会跟踪给定类型何时实现其中一个特质,并在函数返回其中一个类型时,特别标住它。这是“Important Traits”对话框,在函数旁边显示为 圆圈-i 按钮,单击此按钮可显示对话框。

在标准库中,符合条件的特质是Iteratorio::Read,和io::Write。但是,这些特质不是硬编码列表,而是具有特殊的标记属性:#[doc(spotlight)]。这意味着您可以将此属性应用于您自己的特质,并将其包含在文档中的“Important Traits”对话框中。

#[doc(spotlight)]属性目前需要#![feature(doc_spotlight)]功能守卫。有关更多信息,请参阅它在不稳定的书中的章节它的跟踪问题

从文档中,排除某些依赖项

标准库使用多个依赖项,而这些依赖项又使用标准库中的几种类型和特质。此外,编译器内部,有几个箱子,不被认为是官方标准库的一部分,因此会在文档中分散。排除他们的箱子文件是不够的,因为关于特质实现的信息,会出现在类型和特质的页面上,且可以是不同的箱子!

为防止内部类型包含在文档中,标准库会为其extern crate声明添加了属性:#[doc(masked)]。这会导致 Rustdoc 在构建特质实现列表时,“屏蔽掉”这些包中的类型。

#[doc(masked)]属性旨在在内部使用,并且需要#![feature(doc_masked)]功能守卫。有关更多信息,请参阅它在不稳定的书中的章节它的跟踪问题

包含外部文件,把它作为 API 文档

按照设计RFC 1990,Rustdoc 可以读取外部文件以用作类型的文档。如果某些文档太长,以至于会破坏读取源代码的流程,这将非常有用。不把全部文档内联,而是用#[doc(include = "sometype.md")](这里的sometype.md是一个箱子中lib.rs邻近的文件)将要求 Rustdoc 读取该文件并使用它,就好像它是内联编写的一样。

#[doc(include = "...")]目前需要#![feature(external_doc)]功能守卫。有关更多信息,请参阅它在不稳定的书中的章节它的跟踪问题

在文档搜索中,为某项添加别名

此功能允许您为某项添加别名,这样当使用rustdoc搜索时,会接触到doc(alias)属性。例:


# #![allow(unused_variables)]
#![feature(doc_alias)]

#fn main() {
#[doc(alias = "x")]
#[doc(alias = "big")]
pub struct BigX;
#}

然后,输入“x”或“big”,rustdoc搜索会找到,并优先显示BigX结构。

不稳定的命令行参数

通过将命令行标志传递给 Rustdoc 来启用这些功能,但是有问题的标志本身被标记为不稳定。要使用这些选项中的任何一个,请在命令行上传递-Z unstable-options和问题标志。要从 Cargo 执行此操作,您可以使用RUSTDOCFLAGS环境变量,或cargo rustdoc命令。

译者:(下面的)内容 - content: 代指要渲染的 HTML 内容。

--markdown-before-content:在内容之前,包含渲染的 Markdown

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --markdown-before-content extra.md
$ rustdoc README.md -Z unstable-options --markdown-before-content extra.md

就像--html-before-content,这允许您在<body>标签内部,但在其他rustdoc正常生成内容之前,插入额外的内容(extra.md)。但不是直接插入文件,rustdoc会通过 Markdown 渲染器过滤文件,再把结果插入。

--markdown-after-content:在内容之后,包含渲染的 Markdown

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --markdown-after-content extra.md
$ rustdoc README.md -Z unstable-options --markdown-after-content extra.md

就像--html-after-content,这允许您在<body>标签内部,但在其他rustdoc正常生成内容之后,插入额外的内容(extra.md)。但不是直接插入文件,rustdoc会通过 Markdown 渲染器过滤文件,再把结果插入。

--playground-url:控制游乐场的位置

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --playground-url https://play.rust-lang.org/

渲染一个箱子的文档时,此标志提供 Rust Playground 的基本 URL,用于生成Run纽扣。不像--markdown-playground-url,此参数适用于独立的 Markdown 文件Rust 箱。这与添加#![doc(html_playground_url = "url")]到你箱子根目录的方式相同。在章节#[doc]属性有提到。请注意正式的 Rust Playgroundhttps://play.rust-lang.org,它没有任何可用的非标准库箱子,所以,如果你的例子需要你的箱子,请确保你提供的游乐场有你的箱子。

如果--playground-url--markdown-playground-url两者在渲染独立的 Markdown 文件时出现,且 URL 都给定,--markdown-playground-url将优先考虑。如果--playground-url#![doc(html_playground_url = "url")]两者在渲染箱子文档时存在,属性(后者)将优先。

--crate-version:控制箱子版本

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --crate-version 1.3.37

rustdoc收到这个标志后,它会在箱子根文档的侧边栏中,打印一个额外的“Version (version)”。您可以使用此标志来区分库文档的不同版本。

--linker:控制用于文档测试的链接员

使用此标志如下所示:

$ rustdoc --test src/lib.rs -Z unstable-options --linker foo
$ rustdoc --test README.md -Z unstable-options --linker foo

rustdoc运行您的文档测试,它需要在运行它们之前,编译并将测试链接为可执行文件。此标志可用来更改,这些可执行文件上使用的链接员。这相当于传递-C linker=foorustc

--sort-modules-by-appearance:控制模块页面上的项的排序方式

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --sort-modules-by-appearance

通常,当rustdoc在模块页面中打印项,它将按字母顺序排序(考虑它们的稳定性,以及以数字结尾的名称)。给rustdoc这个标志将禁用这种排序,选择按照它们在源代码中出现的顺序打印项。

--themes:提供其他主题

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --themes theme.css

rustdoc这个标志将使您的主题复制到生成的箱子文档中,并在主题选择器中启用。注意rustdoc将拒绝您的主题文件,如果它没有“light”主题的所有样式(元素名)。欲知详情,看下面的--theme-checker

--theme-checker:验证主题 CSS 的有效性

使用此标志如下所示:

$ rustdoc -Z unstable-options --theme-checker theme.css

在将您的主题包含在箱子文档中之前,rustdoc会把它包含的所有 CSS 规则,与默认包含的“light”主题进行比较。使用此标志将允许您在rustdoc拒绝你的主题,能够查看缺少哪些规则。

--resource-suffix:修改箱子文档中的 CSS / JavaScript 名称

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --resource-suffix suf

渲染文档时,rustdoc创建几个 CSS 和 JavaScript 文件作为输出的一部分。由于所有这些文件都是每个页面要链接的,因此如果您需要专门缓存它们,更改它们的位置可能会很麻烦。此标志将重命名输出中的所有这些文件,以在文件名中包含后缀。例如用上面的命令,light.css会成为light-suf.css

--display-warnings:记录或运行文档测试时显示警告

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --display-warnings
$ rustdoc --test src/lib.rs -Z unstable-options --display-warnings

此标志背后的意图是允许用户查看其库或其文档测试中,发生的警告,这些警告通常会被抑制。然而,由于一个错误,这个标志不是 100%按预期工作。有关详细信息,请参阅问题链接

--extern-html-root-url:控制 rustdoc 如何链接到非本地箱子

使用此标志如下所示:

$ rustdoc src/lib.rs -Z unstable-options --extern-html-root-url some-crate=https://example.com/some-crate/1.0.1

通常,当 rustdoc 想要链接到来自不同箱子的类型时,它会在两个地方查找:输出目录中已存在的文档,或者是另一个箱子中的#![doc(doc_html_root)]。但是,如果要链接到这两个位置中都不存在的文档,可以使用这些标志来控制该行为。当--extern-html-root-url使用,并与您的某个依赖项(名称)匹配,rustdoc 会使用这些文档的 URL。请记住,如果这些文档存在于输出目录中,那些本地文档仍将覆盖此标志。

-Z force-unstable-if-unmarked

使用此标志如下所示:

$ rustdoc src/lib.rs -Z force-unstable-if-unmarked

这是一个内部标志,用于标准库和应用程序的编译器,将#[unstable]属性应用到任何没有其他稳定属性的依赖箱子。这允许rustdoc能够为编译器包和标准库生成文档,作为建造这些箱子时,提供给rustc的等效命令行参数。

--index-page:为文档提供顶层网面

此功能允许您生成,给定 markdown 文件的索引页面。一个很好的例子是rust 文档索引页

有了这个,你将有一个页面,你可以在你的箱子顶部,尽可能自定义定制。

使用index-page选项,也会启用enable-index-page

--enable-index-page:为文档生成默认索引页

此功能允许,生成列出生成箱子的默认索引页。

--static-root-path:控制静态文件在 HTML 输出中的加载方式

使用此标志如下:

$ rustdoc src/lib.rs -Z unstable-options --static-root-path '/cache/'

此标志控制 RustDoc 如何链接到 HTML 页面上的静态文件。如果您托管了许多,由同一版本的 RustDoc 生成的箱子文档,则可以使用此标志将 RustDoc 的 CSS、javascript 和字体文件缓存在单个位置,而不是每个“Doc root”(将生成的箱子文档,分组到同一输出目录,如cargo doc)每个箱子文件(如搜索索引)仍将从文档根目录加载,但从给定路径,加载并重命名为--resource-suffix

--persist-doctests:运行后保留 doctest 可执行文件

使用此标志如下:

$ rustdoc src/lib.rs --test -Z unstable-options --persist-doctests target/rustdoctest

此标志允许您在编译或运行 doctest 可执行文件之后保留它们。通常,RustDoc 会在测试后立即丢弃编译好的 doctest,但使用此选项,您可以保留这些二进制文件,以进行进一步的测试。

--show-coverage:计算文档的项(item)百分比

使用此标志如下:

$ rustdoc src/lib.rs -Z unstable-options --show-coverage

如果您想确定箱子中,文档化了多少项,请将此标志传递给 RustDoc。当它收到这个标志时,它将统计您的箱子中,有文档的公共项,并打印出计数和百分比,而不是生成文档。

一些方法说明了 RustDoc 在该指标中的重要性:

  • RustDoc 只计算您箱子中的项(即从其他箱子重新导出的项,不计算在内)。
  • 直接写入内在 impl 块的文档不计算在内,即使显示了它们的文档注释,因为 Rust 代码中的常见模式是将所有内在方法写入同一 impl 块。
  • trait 实现中的项不计算在内,因为这些 impl 将从 trait 本身继承任何文档。
  • 默认情况下,只计算公共项。要计算私有项,请同时传递--document-private-items

没有文档(注释)的公共项,可以通过内置的missing_docslint 看到,没有文档(注释)的私有项,可通过 clippy missing_docs_in_private_itemslint 查看。