#[doc] 属性

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

#[doc] 最基本的作用就是处理文档内容。就是说,/// 就是 #[doc] 的语法糖。下面的两行注释是一样的:

#![allow(unused)] fn main() { /// This is a doc comment. #[doc = " This is a doc comment."] fn f() {} }

(请注意属性版本的开始的空格。)

在大多数情况下,///#[doc] 更容易使用。一种后面更容易使用的场景是给宏生成文档;collapse-docs 会组合多个 #[doc]属性为一条文档注释,比如:

#![allow(unused)] fn main() { #[doc = "This is"] #[doc = " a "] #[doc = "doc comment"] fn f() {} }

这样可能感觉更灵活。注意这跟下面的写法是一样的:

#![allow(unused)] fn main() { #[doc = "This is\n a \ndoc comment"] fn f() {} }

给出的文档会渲染成 markdown,会删除换行符。

另一个有用的场景是引入外部文件:

#[doc = include_str!("../README.md")] fn f() {}

doc 属性有更多的选项!不会包含在输出中,但是可以控制输出的表示。我们将它们分为两大类:在 crate 层面使用的,和在 item 层面使用的。

crate 层面

这些选项控制文档在 crate 层面如何表示。

html_favicon_url

这个 doc 属性让你控制你的文档图标。

#![allow(unused)] #![doc(html_favicon_url = "https://example.com/favicon.ico")] fn main() { }

这会在你的文档中加入 <link rel="shortcut icon" href="{}">,属性的值会填入 {}

如果你不使用这个属性,就没有图标。

html_logo_url

这个 doc 属性可以让你控制左上角的 logo。

#![allow(unused)] #![doc(html_logo_url = "https://example.com/logo.jpg")] fn main() { }

这会在你的文档中加入 <a href='index.html'><img src='{}' alt='logo' width='100'></a>,属性的值会填入 {}

如果你不使用这个属性,就没有 logo。

html_playground_url

这个 doc 属性让你控制文档示例中的 "run" 按钮的请求到哪里。

#![allow(unused)] #![doc(html_playground_url = "https://playground.example.com/")] fn main() { }

现在,当你按下 "run",会向对应网站发出请求。

如果你没有使用这个属性,没有运行按钮。

issue_tracker_base_url

这个 doc 属性在标准库中使用最多;当一个特性未稳定时,需要提供 issue number 来追踪这个特性。rustdoc 使用这个 number,加入到给定的基本 URL 来链接到追踪的网址。

#![allow(unused)] #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] fn main() { }

html_root_url

#[doc(html_root_url = "…")] 属性的值表明了生成外部 crate 的 URL。当 rustdoc 需要生成一个外部 crate item 的链接时,首先检查本地外部 crate 的文档,如果存在直接链接指向。如果失败,就会使用 --extern-html-root-url 命令行参数的值,如果没有这个参数,才会使用 html_root_url ,如果还是无效,外部 item 不会链接。

#![allow(unused)] #![doc(html_root_url = "https://docs.rs/serde/1.0")] fn main() { }

html_no_source

默认情况下,rustdoc 会包含你的源码链接到文档中。 但是如果你这样写:

#![allow(unused)] #![doc(html_no_source)] fn main() { }

就不会。

test(no_crate_inject)

默认情况下,rustdoc 会自动加一行 extern crate my_crate; 到每个文档测试中。 但是如果你这样写了:

#![allow(unused)] #![doc(test(no_crate_inject))] fn main() { }

就不会。

test(attr(...))

这个 doc 属性允许你对你所有的文档测试加上某个属性。比如,如果你想要你的文档测试存在警告时失败,可以这样写:

#![allow(unused)] #![doc(test(attr(deny(warnings))))] fn main() { }

item 层面

这些 #[doc] 属性单独给 item 使用,控制 item 文档表示。

inline and no_inline

这两个属性可以用于 use 声明。比如,考虑如下 Rust 代码:

pub use bar::Bar; /// bar docs pub mod bar { /// the docs for Bar pub struct Bar; } fn main() {}

文档会生成 "Re-exports" 小节,表示 pub use bar::Bar; 其中 Bar 会链接到自己的页面。

如果我们将代码改为:

#[doc(inline)] pub use bar::Bar; pub mod bar { pub struct Bar; } fn main() {}

Bar 就会出现在 Structs 小节,就像 Bar 就定义在顶层一样,而不是 pub use 的。

然后我们修改原始的例子,使 bar 私有:

pub use bar::Bar; /// bar docs mod bar { /// the docs for Bar pub struct Bar; } fn main() {}

这里,因为 bar 不是公共的,Bar 没有自己的页面,所有没有链接可以指向。rustdoc 将会内联定义,所以会得到与 #[doc(inline)] 一样的结果:Bar 就会出现在 Structs 小节,就像 Bar 就定义在顶层一样。如果我们加上 no_inline 属性:

#[doc(no_inline)] pub use bar::Bar; /// bar docs mod bar { /// the docs for Bar pub struct Bar; } fn main() {}

现在我们有了 Re-exports,并且 Bar 没有链接到任何页面。

一个特殊情况:在 Rust 2018 以及更高版本,如果你 pub use 你的依赖,rustdoc 不会作为 modules 内联除非你加上 #[doc(inline)]

hidden

任何标注了 #[doc(hidden)] 的 item 不会出现在文档中,除非 strip-hidden pass 被删除。

alias

这个属性给搜索索引增加了别名。

让我们举个例子:

#![allow(unused)] fn main() { #[doc(alias = "TheAlias")] pub struct SomeType; }

现在,如果你输入 "TheAlias" 搜索,也会显示 SomeType。当然如果你输入 SomeType 也会显示 SomeType

FFI 例子

文档属性在写 c 库的 bingding 时尤其有用。比如,我们有一个下面这样的 C 函数:

int lib_name_do_something(Obj *obj);

它输入一个指向 Obj 类型的指针返回一个整数。在 Rust 中,可能会这样写:

pub struct Obj { inner: *mut ffi::Obj, } impl Obj { pub fn do_something(&mut self) -> i32 { unsafe { ffi::lib_name_do_something(self.inner) } } }

函数已经被转换为一个方法便于使用。但是如果你想要寻找 Rust 相当的 lib_name_do_something,你没有办法做到。

为了避免这个限制,我们只需要在 do_something 方法加上 #[doc(alias = "lib_name_do_something")],然后就可以了!

用户可以直接搜索 lib_name_do_something 然后找到Obj::do_something