Rust 之四 文档规范、编码规范
概述
编程语言除了有语言标准之外,还有一系列其他约定俗成的标准,例如,项目管理、文档规范、编码规范等等。很多早期的编程语言则没有一个统一的标准,而 Rust 编程语言作为一个完全开源的后起之秀,在诞生之初就针对性的解决完善了这些问题!
文档规范
文档一直都是一个项目最为关键但是很麻烦的工作。Rust 官方专门为文档的编写制定了相关规范,并以此编写了 Rust 相关的各种文档。为此,Rust 官方还提供了一个名为 mdBook 的文档处理工具,以方便编写独立文档,同时还提供了一个名为 rustdoc 的文档处理工具,用于将源码中的注释直接生成文档。
mdBook
mdBook 是一个将一系列 Markdown 文档(.md)创建为一套 HTML 文档的命令行工具。它是创建产品或 API 文档、教程、课程材料或任何需要简洁、易于导航和可定制的演示文稿的理想工具。Rust 提供的绝大多数文档都是使用 mdBook 来构建的,汇总如下:
安装
默认安装 Rust 后比不会安装 mdbook,我们需要使用 cargo install mdbook 手动进行安装,mdbook 可执行文件会被放到 .cargo/bin 目录中。也可以直接在 https://github.com/rust-lang/mdBook/releases 上下载预编译好的可执行文件来使用!或者直接从源码构建出可执行程序!
目录结构
使用 mdbook init xxx 命令就会创建出名为 xxx 的文档目录结构,自动生成如下所示的目录结构
-
book.toml文件按是配置文件 -
新增的 Markdown文章都要放到 src 目录下,可以自行创建子目录来进行分类存放
-
src/SUMMARY.md是所有文章的目录,新增的 Markdown文章都需要在这里面写一下 -
book文件夹用于存放 mdBook 构建后产生的 HTML 的文档
生成文档
在文档目录中,执行 mdbook build 就可以一键生成 HTML 格式的静态网页文档,默认存到当前目录的 book 文件夹中。在编写时,可以使用 mdbook serve 命令可以启动本地 Web 服务器,我们可以直接在浏览器中以 localhost 进行预览
rustdoc
rustdoc 是 Rust 官方的文档处理工具,并附带 Rust 编译工具链发布,这个工具主要是用来自动收集当前项目源码文件中的各种注释来生成对应文档。它接受一个 crate root 文件(也支持一个 markdown 文件)作为参数,然后生成 HTML,CSS 和 JavaScript 文件等组成一套静态网页文档。如下官方文档就是使用 rustdoc 生成的:
| 名称 | 在线地址 | 源码地址 |
|---|---|---|
| The Rust Standard Library | https://doc.rust-lang.org/std/index.html | <> |
| The Rust Standard Library | https://doc.rust-lang.org/core/index.html | <> |
| The Rust Standard Library | https://doc.rust-lang.org/core/index.html | <> |
基本格式
rustdoc 会提取源码文件中特定格式的注释(官方称为文档注释)来生成文档,rustdoc 规定了用于生成的文档的注释必须以 /// 或者 //! 开头,并且注释的内容主要使用 Markdown 语法来进行编写。
///用于放在函数、结构体、变量等代码前面以对代码进行注释,称为 outer documentation,示例如下:
//!用于放到一个源码文件的开头给一个源码文件注释,称为 inner documentation。示例如下:
- 当它位于 root crate 文件时,那么它就是文档主页的注释
- 其最后面需要加一个空行
- 可以在自己的
src/lib.rs或main.rs的开头添加#![warn(missing_docs)],而如果是一个要共享的库则可添加#![deny(missing_docs)] - 使用
#[doc(hidden)]可以屏蔽将之后的内容提取到文档中
生成文档
在项目源码目录中直接使用 cargo doc 就可以在 target/**/doc 目录下一键生成 HTML 格式的静态网页文档!
编码规范
代码的命名规范、风格、注释方式一直都是程序员比较头疼的一个问题,因为不同的人总有自己的想法和风格。Rust 官方则对 Rust 编程制定了一系列的编码规范,并提供了 rustfmt 这个代码格式化工具来帮助程序员处理这些问题。Rust 语言社区内其实分散着很多编码规范:
- 官方|Rust API 编写指南
- 官方 | Rust Style Guide
- Rust’s Unsafe Code Guidelines Reference
- 法国国家信息安全局 | Rust 安全(Security)规范
- Apache Teaclave 安全计算平台 | Rust 开发规范
- PingCAP | 编码风格指南(包括 Rust 和 Go 等)
- Google Fuchsia 操作系统 Rust 开发指南
- RustAnalyzer 编码风格指南
- 使用 Rust 设计优雅的 API
- Rust FFI 指南
命名规范
Rust 倾向于在“类型”级的结构中使用大驼峰( UpperCamelCase) 命名风格,在 “变量、值(实例)、函数名”等结构中使用蛇形( snake_case)命名风格。针对不同的类型,Rust 官方建议的命名方式如下表所示:
| 类型 | 命名规则 | 示例 |
|---|---|---|
| Crates / Package | snake_case | cook.rs make_bin.rs |
| Modules | snake_case | Mod cook { … } |
| Types | UpperCamelCase | |
| Traits | UpperCamelCase | |
| Enum variants | UpperCamelCase | enum WebEvent { PageLoad, PageUnload, KeyPress(char), Paste(String), Click { x: i64, y: i64 }, } |
| Functions | snake_case | fn calc_crc() { … } |
| Methods | snake_case | |
| General constructors | new or with_more_details | |
| Conversion constructors | from_some_other_type | |
| Macros | snake_case! | macro_rules! macro_name { // 宏规则 ($arg1:pat, $arg2:expr) => { // 生成的代码 }; } 使用时 macro_name!() 来使用 |
| Local variables(包括函数的形参和实参) | snake_case | let first_name = “zcs” |
| Statics | SCREAMING_SNAKE_CASE | static FIRST_NAME : &str = “zcs”; |
| Constants | SCREAMING_SNAKE_CASE | const FIRST_NAME : &str = “zcs” |
| Type parameters | concise UpperCamelCase, usually single uppercase letter: T | |
| Lifetimes | short lowercase, usually a single letter: 'a, 'de, 'src | |
| Features | snake_case |
-
通常使用
动词-宾语[-error]这种结构。例如,标准库中有JoinPathsError、ParseBoolError等 -
在 UpperCamelCase 情况下,由首字母缩写组成的缩略语和复合词的缩写,应算作单个词。比如,应该使用 Uuid 而非 UUID,使用 Usize 而不是 USize,或者是 Stdin 而不是 StdIn。
-
在 snake_case 中,首字母缩写和缩略词是小写的 is_xid_start。
-
在 snake_case 或者 SCREAMING_SNAKE_CASE 情况下,每个词不应该由单个字母组成,除非这个字母是最后一个词。比如,使用 btree_map 而不使用 b_tree_map,使用 PI_2 而不使用 PI2 。
-
由于历史问题,包名有两种形式 snake_case 或 kebab-case ,但实际在代码中需要引入包名的时候,Rust 只能识别 snake_case,也会自动将 kebab-case 识别为 kebab_case。所以建议使用 snake_case。
-
类型转换要遵守 as_,to_,into_ 命名惯例。类型转换应该通过方法调用的方式实现,其中的前缀规则如下:
方法前缀 性能开销 所有权改变 示例 as_ Free borrowed -> borrowed str::as_bytes() 把 str 变成 UTF-8 字节数组,性能开销是 0。输入是一个借用的 &str,输出也是一个借用的 &str to_ Expensive borrowed -> borrowed
borrowed -> owned (non-Copy types)
owned -> owned (Copy types)Path::to_str 会执行一次昂贵的 UTF-8 字节数组检查,输入和输出都是借用的。对于这种情况,如果把方法命名为 as_str 是不正确的,因为这个方法的开销还挺大 into_ Variable owned -> owned (non-Copy types) String::into_bytes() 返回 String 底层的 Vec<u8>数组,转换本身是零消耗的。该方法获取 String 的所有权,然后返回一个新的有独立所有权的Vec<u8>- 当一个单独的值被某个类型所包装时,访问该类型的内部值应通过 into_inner() 方法来访问。
- 如果 mut 限定符在返回类型中出现,那么在命名上也应该体现出来。例如,Vec::as_mut_slice 就说明它返回了一个 mut 切片
-
读访问器(Getter)的名称遵循 Rust 的命名规范
-
一个集合上的方法,如果返回迭代器,需遵循命名规则:iter,iter_mut,into_iter
fn iter(&self) -> Iter // Iter implements Iterator<Item = &U> fn iter_mut(&mut self) -> IterMut // IterMut implements Iterator<Item = &mut U> fn into_iter(self) -> IntoIter // IntoIter implements Iterator<Item = U> -
迭代器的类型应该与产生它的方法名相匹配。例如形如 into_iter() 的方法应该返回一个 IntoIter 类型
代码风格
制定统一的编码风格可以大大提升代码的可读性,让日常代码维护和团队之间审查代码更加方便。Rust 官方定义了 Rust 代码的整体风格,并且提供了自动化格式化工具 rustfmt 来帮助我们处理代码风格。
-
每级缩进必须为 4 个空格,而不是制表符(
TAB)进行代码对齐 -
一行的最大宽度为 100 个字符,但是完全是注释的行的长度应限制为 80 个字符
-
优先使用块缩进而不是视觉缩进
// Block indent a_function_call( foo, bar, ); // Visual indent a_function_call(foo, bar); -
在任何类型的逗号分隔列表中,在后跟换行符时使用尾随逗号
-
用零或一个空行分隔项目和语句。
-
函数定义,注意各个关键字的顺序,以及
{}的位置[pub] [unsafe] [extern ["ABI"]] fn foo(arg1: i32, arg2: i32) -> i32 { ... } -
更详细的格式参见 https://doc.rust-lang.org/nightly/style-guide/
注释风格
在 Rust 中,注释可以分为普通注释和文档注释两类。普通注释使用 // 或 /* ... */ ,文档注释使用 ///(等同于把注释内容写入 #[doc="..."] 里)、//!(等同于把注释内容写入 #![doc=“…”] 里)。注意,注释需要放到要注释的内容的前面。
-
//是单行注释,注释内容直到行尾
- 可以嵌套,但是一般没有这么用的
- 不能放到代码语句内部,只能放到代码结尾
- 优先选择行注释 (
//) 而不是块注释 (/* ... */)
-
/* ... */为块注释,注释内容在/*和*/之间可以任意多行
- 块注释可以嵌套,但是一般没有这么用的
- 多行块注释通常在每行前面加一个
*是常用的风格,但不是必须得 - 块注释可以插入到代码语句内部

-
///也是单行注释,也有对应的块注释格式为/** ... */,用于放在函数、结构体、变量等代码前面以对代码进行注释,称为 outer documentation,///开头的注释会被rustdoc提取用于生成文档,示例如下:
- 注释的内容主要使用 Markdown 语法来编写
- 优先选择行注释 (
///) 而不是块注释 (/** ... */)
-
//!单行注释,也有对应的块注释格式为/*! ... */,用于放到一个源码文件的开头给一个源码文件注释,称为 inner documentation。//!开头的注释会被rustdoc提取用于生成文档,示例如下:
- 注释的内容主要使用 Markdown 语法来编写
- 当它位于 root crate 文件中时,那么它就是文档主页的注释
- 其最后面需要加一个空行
-
孤立的 CRs(
\r),如果其后没有紧跟有 LF(\n),则不能出现在文档型注释中
参考
- https://course.rs/cargo/reference/workspaces.html
- https://rust-coding-guidelines.github.io/rust-coding-guidelines-zh/
更多推荐




所有评论(0)