news 2026/10/16 2:39:32

Rust API 文档注释编写规范:RFC 505 与 RFC 1574 官方约定全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Rust API 文档注释编写规范:RFC 505 与 RFC 1574 官方约定全解析
  • 文档

【免费下载链接】rfcs

RFCs for changes to Rust

项目地址:https://gitcode.com/gh_mirrors/rf/rfcs
点击查看免费下载

本指南系统讲解 Rust 项目(含 rustc 自身与标准库)的 API 文档注释(doc comment)编写规范,其源头是 2014 年提出的 RFC 505 及 2016 年修订它的 RFC 1574。读完本文,你将掌握从注释语法选择、摘要句撰写、Markdown 排版,到类型引用、文档链接、模块级与类型级文档分工的完整约定,并能直接套用到自己 crate 的 rustdoc 输出中。

规范从何而来:RFC 505 的定位与演进

RFC 505 是一份"约定型 RFC"(conventions RFC),发布于 2014-12-08,其核心使命是:为 Rust 项目(包括 Rust 语言本身)提供编写 API 文档的指导。它的动机非常直白:

Documentation is an extremely important part of any project. It's important that we have consistency in our documentation.

即文档是任何项目的重要组成部分,保持文档的一致性至关重要。值得注意的一点是,RFC 505 提出的大部分准则在当时已被社区日常遵循,这份 RFC 的价值在于为这些"约定俗成"的行为提供动机和澄清,把它们从隐性共识变成可引用的显式规范。

该 RFC 已被 RFC 1574 修订,后者在 Appendix A(合并版规范全文) 中给出了 RFC 505 与自身修改合并后的完整文本,本文后续内容即按该合并版展开。

适用范围:多数准则适用于任何 Rust 项目;但有一部分专门针对 rustc 自身和标准库的文档(如"English"一节),原文已在正文中单独标注。规划规范时原文还列出了一份标准的小节清单(Examples / Panics / Failure),这在合并版中被更新与扩充,详见下文"Markdown 用法"。

注释形式:用行注释代替块注释

第一条约定是注释形式层面的:避免块注释,优先使用行注释。例如描述一段行为时,RFC 推荐:

// Wait for the main task to return, and set the process error code // appropriately.

而不是:

/* * Wait for the main task to return, and set the process error code * appropriately. */

其次是内部文档注释(inner doc comment)的使用边界://!只能用于撰写 crate 级和 module 级文档,除此之外不要使用。当要注释一个mod块时,应优先把///写在块外面:

/// This module contains tests mod tests { // ... }

而不是写在块内部:

mod tests { //! This module contains tests // ... }

这条约定的实践价值在于://!的语义是把文档"注入"到当前容器(crate/module)内部,因此它天然只适合模块与 crate 概览;而///用于具体条目(函数、结构体、trait 等),两者分工明确后,读者看到//!就能立刻预期后面跟着的是整体概览,看到///则预期是某个 API 条目的说明。

摘要句与整体格式:第一行决定 rustdoc 的印象分

任何 doc comment 的第一行应当是一句单行短句,对该代码给出摘要(summary)。这一行会被 rustdoc 在索引页、侧边栏、搜索结果等处反复用作摘要描述,因此保持简短非常划算。紧接着的格式要求有三条:

  • 标点完备:所有 doc comment(包括摘要行)都应使用正确的标点符号;优先写完整句子,而不是碎片化短语。
  • 人称与时态固定:摘要行应使用第三人称单数现在时陈述式(third person singular present indicative)。说白了,写 "Returns" 而不是 "Return"。这条约定直接决定了 rustdoc 中大量标准库文档的第一行形态,例如本仓库 text/1123-str-split-at.md 中str::split_at的注释第一行就是 "Divide one string slice into two at an index.",text/1328-global-panic-handler.md 中 panic API 的第一行则是 "Unregisters the current panic handler, returning it."、"Returns the payload associated with the panic." 等——都是第三人称现在时的完整句子。

在合并版规范中,"Summary sentence"一节(Appendix A)再次强调了这两点,并将其明确界定为**对 API 文档(而非普通注释)**的要求。

Markdown 用法:排版、代码块、小标题与引用风格链接

doc comment 内部允许使用 Markdown 排版,RFC 对用法给出了明确约束。

用一级标题划分小节

使用顶层标题#在注释内划分小节。RFC 505 列出的常见小节标题为:

  • Examples
  • Panics
  • Failure

合并版(RFC 1574)将清单更新为:

  • Examples
  • Panics
  • Errors
  • Safety
  • Aborts
  • Undefined Behavior

一个重要细节:即使只包含一个示例,也使用复数形式 "Examples" 而不是 "Example"。理由是为了让未来的工具处理更一致(不必同时兼容单复数两种标题)。本仓库中大量标准库 API 提案都严格遵循了这一约定,例如 text/0574-drain-range.md 中Vec::drain的注释同时使用了 "Panics" 与 "Safety" 风格的小节组织,text/1123-str-split-at.md 中的split_at注释则依次包含 "Panics" 与 "Examples" 两节。

行内代码与多行代码块

  • 用反引号(`)标注句内的代码片段;
  • 用三反引号(```)撰写较长的示例:
This code does something cool. ```rust let x = foo(); x.bar();
### 代码块语言标注:rustdoc 会执行所有 Rust 示例 在合适的地方利用 rustdoc 的格式化指令,为三反引号代码块标注对应的语言:
println!("Hello, world!");
puts "Hello"
RFC 505 主张尽量显式标注 `rust`,理由是让 GitHub 等不会默认按 Rust 高亮的平台也能正确着色。合并版则做了细化:**在 API 文档中可以依赖 rustdoc 的默认值(默认即为 rust)**,例如: ```rust /// For example: /// /// ``` /// let x = 5; /// ```

但在长文档(long-form documentation)中仍应始终显式标注rust。无论哪种情况,一条硬性约束不变:rustdoc 会实际编译并运行文档内嵌入的所有 Rust 示例,因此凡是非 Rust 的代码块必须正确标注语言,否则你的文档测试(doctest)会失败。这正是"标注语言"从美观问题升格为正确性问题的根本原因。

引用风格链接优于内联链接

引用和引证应使用"引用风格"(reference style)链接。RFC 505 推荐的写法:

[Rust website][1] [1]: http://www.rust-lang.org

优于:

[Rust website](http://www.rust-lang.org)

合并版在此基础上进一步简化:优先省略第二个[](即 Markdown 的 shortcut reference link 形式):

[Rust website] [Rust website]: http://www.rust-lang.org

只有当链接文字很长时,才允许使用带标签的完整形式:

This link [is very long and links to the Rust website][website]. [website]: http://www.rust-lang.org

英文规范:标准库统一使用美式英语

"English"一节明确只适用于 rustc 和标准库的文档:所有文档在拼写、语法、标点惯例上统一采用美式英语(American English)。同时 RFC 也给出了一个务实的免责声明:语言是随时间演变的,因此并非每个语法问题都存在唯一正确答案,但通常存在某种正式共识(formal consensus)可供遵循。这条约定保证了标准库文档(以及 rustc 内部文档)在跨贡献者、跨时期协作时风格的一致性。

类型引用与文档链接:把"说清楚"落到实处

合并版新增了三组与措辞和链接有关的约定,它们直接提升文档的可读性与可导航性。

引用类型要用全名

当谈及某个类型时,使用其全名:泛型类型应写Option<T>,而不是Option。唯一例外是 trait bound:写Cow<'a, B>即可,而不用写完整的Cow<'a, B> where B: 'a + ToOwned + ?Sized。另一种可行策略是使用小写泛称词:例如 'string' 可以同时指String或&str,'an option' 可以指代Option<T>。

Link all the things:手动补齐类型链接

Markdown 的一个重大缺陷是不会在 API 文档中自动为类型生成链接。RFC 要求作者自己用引用风格语法补上,以方便阅读:

/// The [`String`] passed in lorum ipsum... /// /// [`String`]: ../string/struct.String.html

这一痛点后来促成了 RFC 1946(intra-doc links) 的诞生。该 RFC 指出现有手工相对链接的三种脆弱性:同一 doc comment 会被渲染到多个目录层级(如模块摘要页与结构体自身页),相对路径无法在所有位置生效;绝对路径在cargo doc --open(file:///URL)和 docs.rs 环境下会失效;一旦 rustdoc 的文件命名方案变更(历史上确实发生过,见 Rust issue #35236),所有手工链接都需要更新。RFC 1946 的解决方案是让链接直接写 Rust item 路径,如Iterator,由 rustdoc 自动解析成可工作的链接——这是"Link all the things"约定在现代 rustdoc 中的官方演化形态。

模块级文档与类型级文档的分工

标准库长期存在模块级文档与类型级文档之间的张力。RFC 举例:当时各类*Cell类型的文档页都写着"refer to the module-level documentation for more details"(更多细节请参阅模块级文档),这迫使读者在多个页面间跳转才能获得完整信息。

正确的分工原则是:

  • 模块级文档给出模块内所有内容的高层概览,应当宽泛、不过度深入;
  • 每个类型完整地自文档化(document itself fully),细节留给类型自己的文档;
  • 允许两者存在少量重复。

这样既保证了模块概览的导航价值,又让每个类型页面可独立阅读,不必"被迫"跳转。

完整示例:一个符合全部规范的 crate

RFC 1574 提供了一个完整的示例 crate(基于作者自己的 ref_slice crate 骨架,作者明确说明重点在文档而非代码质量),完整展示了上述约定如何落地。

在lib.rs中,crate 级文档使用//!描述整体功能、布局(Layout)小节以及类型链接:

//! Turning references into slices //! //! This crate contains several utility functions for taking various kinds //! of references and producing slices out of them. In this case, only full //! slices, not ranges for sub-slices. //! //! # Layout //! //! At the top level, we have functions for working with references, `&T`. //! There are two submodules for dealing with other types: `option`, for //! &[`Option<T>`], and `mut`, for `&mut T`. //! //! [`Option<T>`]: http://doc.rust-lang.org/std/option/enum.Option.html pub mod option; /// Converts a reference to `T` into a slice of length 1. /// /// This will not copy the data, only create the new slice. /// /// # Panics /// /// In this case, the code won't panic, but if it did, the circumstances /// in which it would would be included here. /// /// # Examples /// /// ``` /// extern crate ref_slice; /// use ref_slice::ref_slice; /// /// let x = &5; /// /// let slice = ref_slice(x); /// /// assert_eq!(&[5], slice); /// ``` /// /// A more complex example. In this case, it's the same example, because this /// is a pretty trivial function, but use your imagination. /// /// ``` /// extern crate ref_slice; /// use ref_slice::ref_slice; /// /// let x = &5; /// /// let slice = ref_slice(x); /// /// assert_eq!(&[5], slice); /// ``` pub fn ref_slice<T>(s: &T) -> &[T] { unimplemented!() }

注意其中对# Panics的处理:作者特意演示了"该函数实际不会 panic,但若会 panic,触发条件应写在这里"的占位式写法,明确了该小节的标准语义。unsafe相关 API 则对应# Safety小节,注释中说明若代码需标记为 unsafe,读者应在此了解需要维护的不变量(invariants):

/// Functions that operate on mutable references. /// /// This submodule mirrors the parent module, but instead of dealing with `&T`, /// they're for `&mut T`. mod mut { /// Converts a reference to `&mut T` into a mutable slice of length 1. /// /// This will not copy the data, only create the new slice. /// /// # Safety /// /// In this case, the code doesn't need to be marked as unsafe, but if it /// did, the invariants you're expected to uphold would be documented here. /// /// # Examples /// /// ``` /// extern crate ref_slice; /// use ref_slice::mut; /// /// let x = &mut 5; /// /// let slice = mut::ref_slice(x); /// /// assert_eq!(&mut [5], slice); /// ``` pub fn ref_slice<T>(s: &mut T) -> &mut [T] { unimplemented!() } }

在option.rs中,子模块文档同样以//!开头并链接到Option<T>,类型链接([Option]: ...)在每个需要的位置重复声明,因为引用风格链接的定义是文档局部的:

//! Functions that operate on references to [`Option<T>`]s. //! //! This submodule mirrors the parent module, but instead of dealing with `&T`, //! they're for `&`[`Option<T>`]. //! //! [`Option<T>`]: http://doc.rust-lang.org/std/option/enum.Option.html /// Converts a reference to `Option<T>` into a slice of length 0 or 1. /// /// [`Option<T>`]: http://doc.rust-lang.org/std/option/enum.Option.html /// /// This will not copy the data, only create the new slice. /// /// # Examples /// /// ``` /// extern crate ref_slice; /// use ref_slice::option; /// /// let x = &Some(5); /// /// let slice = option::ref_slice(x); /// /// assert_eq!(&[5], slice); /// ``` /// /// `None` will result in an empty slice: /// /// ``` /// extern crate ref_slice; /// use ref_slice::option; /// /// let x: &Option<i32> = &None; /// /// let slice = option::ref_slice(x); /// /// assert_eq!(&[], slice); /// ``` pub fn ref_slice<T>(opt: &Option<T>) -> &[T] { unimplemented!() }

这个例子值得逐条对照前文规范:摘要句均为第三人称现在时完整句("Converts..."、"This will not copy the data...");小节使用复数 "Examples";多个示例之间用自然语言段落过渡("A more complex example."、"Nonewill result in an empty slice:");示例代码块默认由 rustdoc 编译测试;类型一律使用全名(Option<T>);模块概览(Layout)与类型细节各司其职。

仓库中的实践佐证:规范如何贯穿标准库提案

这份规范并非停留在纸面。本仓库中大量标准库 API 的 RFC 都在 doc comment 层面身体力行地遵循着这些约定,可作为现成的范例阅读:

  • text/0574-drain-range.md 中Vec::drain与String::drain的 API 注释:第一行是第三人称现在时摘要("Creates a draining iterator that clears the specified range..."),随后是 "Panics" 小节说明两种触发 panic 的具体条件(range 递减、上界超出长度、字符边界问题)。
  • text/1123-str-split-at.md 中str::split_at的注释:完整展示了"摘要句 + 补充说明 +# Panics+# Examples(含可运行的 doctest)"的标准四段式结构,示例中还演示了 Unicode 字符串切片这一边界场景。
  • text/1328-global-panic-handler.md 中std::panic模块的 API:每个函数都以 "Returns..."、"Registers..." 式第三人称现在时开头,并以# Panics小节说明嵌套 panic 会导致进程 abort 的极端语义。

这些例子说明:从 2014 年 RFC 505 确立规范起,标准库 API 提案就已经在实际使用这套约定撰写文档,并延续至今。

备选方案与遗留问题

RFC 505 在收尾部分给出了简洁的评估:

  • Drawbacks(缺点):None(无)。
  • Alternatives(备选方案):不制定文档规范(Not having documentation guidelines)。即唯一被考虑的替代方案就是放任自流,而 RFC 明确否定了它——这正是文档一致性需要规范的直接论证。
  • Unresolved questions(未决问题):None(无)。

RFC 1574 则补充了一个诚实的自我审视:有可能 RFC 505 已经足够,而如此细致的补充规范并不必要("It's possible that RFC 505 went far enough, and something this detailed is inappropriate");其备选方案同样是"维持前一个 RFC 的最小约定"。最终结论仍然是:这套合并后的完整规范被采纳,成为 Rust 官方文档写作的事实标准。

总结

RFC 505 与 RFC 1574 共同构成了 Rust API 文档注释的官方规范体系,核心要点可归纳为六条:

  1. 形式:用行注释//,//!仅用于 crate/module 级文档,mod块优先在块外用///;
  2. 摘要句:第一行是第三人称现在时的短句,全文标点完备;
  3. Markdown:用#划分小节(Examples/Panics/Errors/Safety/Aborts/Undefined Behavior),单数内容也用复数标题,代码块正确标注语言(因为 rustdoc 会测试所有 Rust 示例);
  4. 链接:优先引用风格(shortcut reference)链接,并手动为类型补全链接(现代 rustdoc 已演进为 intra-doc links);
  5. 措辞:类型用全名(Option<T>),标准库统一美式英语;
  6. 分层:模块级文档做高层概览,类型文档自文档化,允许少量重复。

将这些约定落实到自己的 crate 中,既能保证 rustdoc 输出的一致性、可搜索性与可测试性,也让自己编写的 API 文档与 Rust 标准库保持同一套话语体系。规范全文可查阅 RFC 505 原文 与 RFC 1574 的合并版 Appendix A。

  • 文档

【免费下载链接】rfcs

RFCs for changes to Rust

项目地址:https://gitcode.com/gh_mirrors/rf/rfcs
点击查看免费下载

相关推荐

上一篇:Stability AI生成模型终极指南:5分钟上手SDXL、SVD、SV3D和SV4D
下一篇:scrcpy 手机投屏到电脑:一条命令起屏,参数怎么调一篇讲清

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 2:37:39

【Docker】镜像制作

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343 &#x1f525; 系列专栏&#xff1a;Docker_秦jh_的博客-CSDN博客 ​​​​​ 目录 Docker 镜像制作 镜像制作及原因 Docker 镜像制作方式 快照方式制作镜像 制作命令 do…

作者头像 李华
网站建设 2026/10/16 2:34:58

N_m3u8DL-RE 流媒体下载实操:从零跑通 DASH/HLS/MSS 完整教程

N_m3u8DL-RE 流媒体下载实操&#xff1a;从零跑通 DASH/HLS/MSS 完整教程 【免费下载链接】N_m3u8DL-RE Cross-Platform, modern and powerful stream downloader for MPD/M3U8/ISM. English/简体中文/繁體中文. 项目地址: https://gitcode.com/GitHub_Trending/nm3/N_m3u8D…

作者头像 李华
网站建设 2026/10/16 2:33:16

Rufus U 盘启动盘制作指南:5 步把 U 盘变成系统安装盘

Rufus U 盘启动盘制作指南&#xff1a;5 步把 U 盘变成系统安装盘 【免费下载链接】rufus The Reliable USB Formatting Utility 项目地址: https://gitcode.com/GitHub_Trending/ru/rufus Rufus 是一款用于格式化 U 盘并制作启动盘的 Windows 免费开源工具&#xff0c;…

作者头像 李华
网站建设 2026/10/16 2:31:54

从 Issue 到 Pull Request:HTML Tidy 5.8.0 贡献指南全解析

【免费下载链接】foo_openlyrics An open-source lyric display panel for foobar2000 项目地址&#xff1a; https://gitcode.com/gh_mirrors/fo/foo_openlyrics 点击查看 免费下载 HTML Tidy 是一款久经考验的 HTML 语法检查与清洗工具&#xff0c;在 foo_openlyrics 项目中…

作者头像 李华
网站建设 2026/10/16 2:30:54

Knative 卸载实战指南:YAML 与 Operator 两种安装方式的完整清理流程

文档教程云原生 【免费下载链接】docs User documentation for Knative components. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/docs1/docs 点击查看 免费下载 导读 本文面向 Kubernetes 管理员&#xff0c;系统讲解如何安全、完整地卸载 Knative 集群组件。Knat…

作者头像 李华