#[doc] 属性

#[doc] 属性允许你控制 rustdoc 如何工作的各个方面。

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

#![allow(unused)]
fn main() {
/// This is a doc comment.
#[doc = r" 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 渲染的,它会删除这些换行符。

另一个用例是将外部文件作为文档包含进来

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

doc 属性还有更多选项!这些选项不涉及输出的文本,而是涉及输出的各个呈现方面。我们将其分为以下两类:在 crate 级别有用的属性,以及在项级别有用的属性。

在 crate 级别

这些选项控制文档在 crate 级别的外观。

html_favicon_url

这种形式的 doc 属性允许你控制文档的 favicon。

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

这会将 <link rel="icon" href="{}"> 放入你的文档中,其中属性的字符串会放入 {} 中。

如果你不使用此属性,则不会有 favicon。

html_logo_url

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

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

这会将 <a href='../index.html'><img src='{}' alt='logo' width='100'></a> 放入你的文档中,其中属性的字符串会放入 {} 中。

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

html_playground_url

这种形式的 doc 属性允许你控制文档示例上的“运行”按钮向何处发出请求。

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

现在,当你按下“运行”时,该按钮将向此域发出请求。请求 URL 将包含 2 个查询参数:codeedition,分别对应于文档中的代码和 Rust 版本。

如果你不使用此属性,则不会有运行按钮。

issue_tracker_base_url

这种形式的 doc 属性主要仅对标准库有用;当某个功能不稳定时,必须给出用于跟踪该功能的 issue 编号。rustdoc 使用此编号,加上此处给出的基本 URL,来链接到跟踪 issue。

#![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 中某个项的链接时,它将首先检查 extern crate 是否已在本地磁盘上记录,如果是,则直接链接到它。如果失败,它将使用 --extern-html-root-url 命令行标志(如果可用)给出的 URL。如果不可用,它将使用 extern crate 中的 html_root_url 值(如果可用)。如果不可用,则外部项将不会被链接。

#![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 将自动在每个 doctest 中添加一行 extern crate my_crate;。但是,如果你包含这个

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

它将不会包含。

test(attr(...))

这种形式的 doc 属性允许你向所有 doctest 添加任意属性。例如,如果你希望 doctest 在存在死代码时失败,你可以添加这个

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

在项级别

这些形式的 #[doc] 属性用于单个项,以控制它们如何被记录。

inlineno_inline

这些属性用于 use 语句,并控制文档的显示位置。例如,考虑以下 Rust 代码

pub use bar::Bar;

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

文档将生成一个“重新导出”部分,并显示 pub use bar::Bar;,其中 Bar 是指向其页面的链接。

如果我们像这样更改 use

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

相反,Bar 将出现在 Structs 部分中,就像 Bar 在顶层定义一样,而不是 pub use'd。

让我们通过使 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 部分中,就像它在顶层定义一样。如果我们添加属性的 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 你的依赖项之一,则除非你添加 #[doc(inline)],否则 rustdoc 不会急切地将其作为模块内联。

如果你想了解有关内联规则的更多信息,请查看 re-exports 章节

hidden

任何使用 #[doc(hidden)] 注释的项都不会出现在文档中,除非删除了 strip-hidden 传递。重新导出的项,如果其祖先之一具有 #[doc(hidden)],则将被视为与私有项相同。

你可以在 re-exports 章节中找到更多信息。

alias

此属性在搜索索引中添加别名。

让我们看一个例子

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

因此,现在,如果你在搜索中输入“TheAlias”,它将显示 SomeType。当然,如果你输入 SomeType,它将按预期返回 SomeType

FFI 示例

此文档属性在为 C 库编写绑定时特别有用。例如,假设我们有一个 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) }
    }
}

该函数已转换为方法,以使其更方便使用。但是,如果你想查找 lib_name_do_something 的 Rust 等价物,你将无法做到这一点。

为了解决此限制,我们只需在 do_something 方法上添加 #[doc(alias = "lib_name_do_something")],然后一切都很好!现在,用户可以直接在我们的 crate 中查找 lib_name_do_something 并找到 Obj::do_something