什么是 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
或.markdown
,rustdoc
将其视为 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)]
一样;Bar
在Structs
部分,好像它是在顶层定义的。如果,我们换成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)]
注释的项不会出现在文档中,除非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 预处理示例的完整算法:
- 插入些常见
allow
属性,包括unused_variables
,unused_assignments
,unused_mut
,unused_attributes
,和dead_code
。小例子经常触发这些 lint。 - 使用
#![doc(test(attr(...)))]
指定的任何属性,会被添加。 - 任何
#![foo]
前缀属性保留为 箱子属性。 - 如果示例不包含
extern crate
,和没有指定#![doc(test(no_crate_inject))]
,那就插入extern crate <mycrate>;
(注意#[macro_use]
的缺乏)。 - 最后,如果示例不包含
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); #}
最后,我们打印出的总和
x
和y
:# #![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>
实现Termination
trait,自然解决了这个限制:
/// 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 版开始,这种简化也适用于Option
s,可以方便地测试,例如迭代器或校验算术,例如:
/// ```
/// 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 代码的习惯,还因为缩进代码块没有办法使用诸如ignore
或should_panic
。
通行证/传递参(Passes)
Rustdoc 有一个名为“passes”的概念。这些是在生成最终输出之前,rustdoc
文档的转变方式。
除了下面描述的 passes 之外,也可以看看这些标志的文档:
默认通行证
默认情况下,rustdoc 将运行一些传递参,即:
strip-hidden
strip-private
collapse-docs
unindent-comments
而,strip-private
暗示strip-private-imports
(剔除私有导入),所以有效地,默认情况下运行所有传递。
这个传递参实现了#[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 crate
和use
语句,而不是项。
不稳定的功能
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 按钮,单击此按钮可显示对话框。
在标准库中,符合条件的特质是Iterator
,io::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=foo
到rustc
。
--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_docs
lint 看到,没有文档(注释)的私有项,可通过 clippy missing_docs_in_private_items
lint 查看。