#[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。