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