Merge pull request #328 from JesseAtSZ/patch-5

Update comment.md
pull/334/head
Sunface 3 years ago committed by GitHub
commit f4098931d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,13 +1,13 @@
# 注释和文档 # 注释和文档
好的代码会说话,好的程序员不写注释,这些都是烂大街的"编程界俚语"。但是,如果你真的遇到一个不写注释的项目或程序员,那一定会对它/他"刮目相看" 好的代码会说话,好的程序员不写注释,这些都是烂大街的“编程界俚语”。但是,如果你真的遇到一个不写注释的项目或程序员,那一定会对它/他“刮目相看”
在之前的章节我们学习了包和模块如何使用,在此章节将进一步学习如何书写文档注释,以及如何使用 `cargo doc` 生成项目的文档,最后将以一个包、模块和文档的综合性例子,来将这些知识融会贯通。 在之前的章节我们学习了包和模块如何使用,在此章节将进一步学习如何书写文档注释,以及如何使用 `cargo doc` 生成项目的文档,最后将以一个包、模块和文档的综合性例子,来将这些知识融会贯通。
## 注释的种类 ## 注释的种类
在 Rust 中,注释分为三类: 在 Rust 中,注释分为三类:
- 代码注释,用于说明某一块代码的功能,用户往往是同一个项目的协作开发者 - 代码注释,用于说明某一块代码的功能,读者往往是同一个项目的协作开发者
- 文档注释,支持`Markdown`, 对项目描述、公共API等用户关心的功能进行介绍同时还能提供示例代码目标用户往往是想要了解你项目的人 - 文档注释,支持 `Markdown`,对项目描述、公共 API 等用户关心的功能进行介绍,同时还能提供示例代码,目标读者往往是想要了解你项目的人
- 包和模块注释,严格来说这也是文档注释中的一种,它主要用于说明当前包和模块的功能,方便用户迅速了解一个项目 - 包和模块注释,严格来说这也是文档注释中的一种,它主要用于说明当前包和模块的功能,方便用户迅速了解一个项目
通过这些注释,实现了 Rust 极其优秀的文档化支持,甚至你还能在文档注释中写测试用例,省去了单独写测试用例的环节,我直接好家伙! 通过这些注释,实现了 Rust 极其优秀的文档化支持,甚至你还能在文档注释中写测试用例,省去了单独写测试用例的环节,我直接好家伙!
@ -27,7 +27,7 @@ fn main() {
} }
``` ```
如上所示,行注释可以放在某一行代码的上方,也可以放在当前代码行的后方. 如果超出一行的长度,需要在新行的开头也加上`//`。 如上所示,行注释可以放在某一行代码的上方,也可以放在当前代码行的后方如果超出一行的长度,需要在新行的开头也加上 `//`
当注释行数较多时,你还可以使用**块注释** 当注释行数较多时,你还可以使用**块注释**
@ -57,7 +57,7 @@ fn main() {
Rust 提供了 `cargo doc` 的命令,可以用于把这些文档注释转换成 `HTML` 网页文件,最终展示给用户浏览,这样用户就知道这个包是做什么的以及该如何使用。 Rust 提供了 `cargo doc` 的命令,可以用于把这些文档注释转换成 `HTML` 网页文件,最终展示给用户浏览,这样用户就知道这个包是做什么的以及该如何使用。
#### 文档行注释 `///` #### 文档行注释 `///`
本书的一大特点就是废话不多,因此我们开门见山: 本书的一大特点就是废话不多,因此我们开门见山
```rust ```rust
/// `add_one` 将指定值加1 /// `add_one` 将指定值加1
/// ///
@ -74,18 +74,18 @@ pub fn add_one(x: i32) -> i32 {
} }
``` ```
以上代码有几点需要注意: 以上代码有几点需要注意
- 文档注释需要位于 `lib` 类型的包中,例如 `src/lib.rs` - 文档注释需要位于 `lib` 类型的包中,例如 `src/lib.rs`
- 文档注释可以使用`markdown`!例如 `# Examples`的标题,以及代码块高亮 - 文档注释可以使用 `markdown`语法!例如 `# Examples` 的标题,以及代码块高亮
- 被注释的对象需要使用`pub`对外可见, 记住:文档注释是给用户看的,**内部实现细节不应该被暴露出去** - 被注释的对象需要使用 `pub` 对外可见,记住:文档注释是给用户看的,**内部实现细节不应该被暴露出去**
咦?文档注释中的例子,为什看上去像是能运行的样子?竟然还是有 `assert_eq` 这种常用于测试目的的宏。 嗯,你的感觉没错,详细内容会在本章后面讲解,容我先卖个关子。 咦?文档注释中的例子,为什看上去像是能运行的样子?竟然还是有 `assert_eq` 这种常用于测试目的的宏。 嗯,你的感觉没错,详细内容会在本章后面讲解,容我先卖个关子。
#### 文档块注释 `/** ... */` #### 文档块注释 `/** ... */`
与代码注释一样,文档也有块注释,当注释内容多时,可以减少`///`的使用: 与代码注释一样,文档也有块注释,当注释内容多时,使用块注释可以减少 `///` 的使用:
````rust ````rust
/** `add_two`将指定值加2. /** `add_two` 将指定值加2
# Examples # Examples
@ -106,23 +106,23 @@ pub fn add_two(x: i32) -> i32 {
很简单,运行 `cargo doc` 可以直接生成 `HTML` 文件,放入*target/doc*目录下。 很简单,运行 `cargo doc` 可以直接生成 `HTML` 文件,放入*target/doc*目录下。
当然,为了方便,我们使用`cargo doc --open`命令,可以在生成文档后,自动在浏览器中打开网页,最终效果如图所示: 当然,为了方便,我们使用 `cargo doc --open` 命令,可以在生成文档后,自动在浏览器中打开网页,最终效果如图所示
<img alt="" src="/img/comment-01.png" class="center" /> <img alt="" src="/img/comment-01.png" class="center" />
非常棒,而且非常简单,这就是 Rust 工具链的强大之处。 非常棒,而且非常简单,这就是 Rust 工具链的强大之处。
#### 常用文档标题 #### 常用文档标题
之前我们见到了在文档注释中该如何使用`markdown`,其中包括`# Examples`标题。除了这个标题,还有一些常用的,你可以在项目中酌情使用: 之前我们见到了在文档注释中该如何使用 `markdown`,其中包括 `# Examples` 标题。除了这个标题,还有一些常用的,你可以在项目中酌情使用
- **Panics**: 函数可能会出现的异常状况,这样调用函数的人就可以提前规避 - **Panics**函数可能会出现的异常状况,这样调用函数的人就可以提前规避
- **Errors**: 描述可能出现的错误及什么情况会导致错误,有助于调用者针对不同的错误采取不同的处理方式 - **Errors**描述可能出现的错误及什么情况会导致错误,有助于调用者针对不同的错误采取不同的处理方式
- **Safety**: 如果函数使用`unsafe`代码,那么调用者就需要注意一些使用条件,以确保`unsafe`代码块的正常工作 - **Safety**:如果函数使用 `unsafe` 代码,那么调用者就需要注意一些使用条件,以确保 `unsafe` 代码块的正常工作
话说回来,这些标题更多的是一种惯例, 如果你非要用中文标题也没问题,但是最好在团队中保持同样的风格 :) 话说回来,这些标题更多的是一种惯例如果你非要用中文标题也没问题,但是最好在团队中保持同样的风格 :)
## 包和模块级别的注释 ## 包和模块级别的注释
除了函数、结构体等Rust项的注释你还可以给模块和包添加注释,需要注意的是,**这些注释要添加到包、模块的最上方** 除了函数、结构体等 Rust 项的注释,你还可以给包和模块添加注释,需要注意的是,**这些注释要添加到包、模块的最上方**
与之前的任何注释一样,包级别的注释也分为两种:行注释 `//!` 和块注释 `/*! ... */` 与之前的任何注释一样,包级别的注释也分为两种:行注释 `//!` 和块注释 `/*! ... */`
@ -143,7 +143,7 @@ pub mod compute;
/// ///
``` ```
运行`cargo doc --open`查看下效果: 运行 `cargo doc --open` 查看下效果:
<img alt="" src="/img/comment-02.png" class="center" /> <img alt="" src="/img/comment-02.png" class="center" />
@ -182,12 +182,12 @@ test src/compute.rs - compute::add_two (line 22) ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.00s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.00s
``` ```
可以看到,文档中的测试用例被完美运行,而且输出中也明确提示了`Doc-tests world_hello`,意味着这些测试的名字叫`Doc test`文档测试. 可以看到,文档中的测试用例被完美运行,而且输出中也明确提示了 `Doc-tests world_hello`,意味着这些测试的名字叫 `Doc test` 文档测试。
> 需要注意的是,你可能需要使用类如 `world_hello::compute::add_one(arg)` 的完整路径来调用函数,因为测试是在另外一个独立的线程中运行的 > 需要注意的是,你可能需要使用类如 `world_hello::compute::add_one(arg)` 的完整路径来调用函数,因为测试是在另外一个独立的线程中运行的
#### 造成 panic 的文档测试 #### 造成 panic 的文档测试
文档测试中的用例还可以造成`panic`: 文档测试中的用例还可以造成 `panic`
```rust ```rust
/// # Panics /// # Panics
/// ///
@ -205,7 +205,7 @@ pub fn div(a: i32, b: i32) -> i32 {
a / b a / b
} }
``` ```
以上测试运行后会`panic`: 以上测试运行后会 `panic`
```console ```console
---- src/compute.rs - compute::div (line 38) stdout ---- ---- src/compute.rs - compute::div (line 38) stdout ----
Test executable failed (exit code 101). Test executable failed (exit code 101).
@ -215,7 +215,7 @@ thread 'main' panicked at 'Divide-by-zero error', src/compute.rs:44:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
``` ```
如果想要通过这种测试,可以添加`should_panic`: 如果想要通过这种测试,可以添加 `should_panic`
```rust ```rust
/// # Panics /// # Panics
/// ///
@ -229,8 +229,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
通过 `should_panic`,告诉 Rust 我们这个用例会导致 `panic`,这样测试用例就能顺利通过。 通过 `should_panic`,告诉 Rust 我们这个用例会导致 `panic`,这样测试用例就能顺利通过。
#### 保留测试,隐藏文档 #### 保留测试隐藏文档
在某些时候,我们希望保留文档测试的功能,但是又要将某些测试用例的内容从文档中隐藏起来: 在某些时候,我们希望保留文档测试的功能,但是又要将某些测试用例的内容从文档中隐藏起来
```rust ```rust
/// ``` /// ```
/// # // 使用#开头的行会在文档中被隐藏起来,但是依然会在文档测试中运行 /// # // 使用#开头的行会在文档中被隐藏起来,但是依然会在文档测试中运行
@ -252,12 +252,12 @@ pub fn try_div(a: i32, b: i32) -> Result<i32, String> {
} }
``` ```
以上文档注释中,我们使用`#`将不想让用户看到的内容隐藏起来,但是又不影响测试用例的运行,最终用户将只能看到那行没有隐藏的`let res = world_hello::compute::try_div(10, 0)?;` : 以上文档注释中,我们使用 `#` 将不想让用户看到的内容隐藏起来,但是又不影响测试用例的运行,最终用户将只能看到那行没有隐藏的 `let res = world_hello::compute::try_div(10, 0)?;`
<img alt="" src="/img/comment-03.png" class="center" /> <img alt="" src="/img/comment-03.png" class="center" />
## 文档注释中的代码跳转 ## 文档注释中的代码跳转
Rust在文档注释中还提供了一个非常强大的功能那就是可以实现对外部项的链接: Rust 在文档注释中还提供了一个非常强大的功能,那就是可以实现对外部项的链接
#### 跳转到标准库 #### 跳转到标准库
```rust ```rust
@ -271,7 +271,7 @@ pub fn add_one(x: i32) -> Option<i32> {
- 在IDE中使用 `Command + 鼠标左键`(mac系统下)`CTRL + 鼠标左键`(win系统下) - 在IDE中使用 `Command + 鼠标左键`(mac系统下)`CTRL + 鼠标左键`(win系统下)
- 在文档中直接点击链接 - 在文档中直接点击链接
再比如,还可以使用路径的方式跳转: 再比如,还可以使用路径的方式跳转
```rust ```rust
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
@ -290,7 +290,7 @@ impl<T> AsyncReceiver<T> {
``` ```
#### 使用完整路径跳转到指定项 #### 使用完整路径跳转到指定项
除了跳转到标准库,你还可以通过指定具体的路径跳转到自己代码或者其它库的指定项,例如在`lib.rs`中添加以下代码: 除了跳转到标准库,你还可以通过指定具体的路径跳转到自己代码或者其它库的指定项,例如在 `lib.rs` 中添加以下代码:
```rust ```rust
mod a { mod a {
/// `add_one` 返回一个[`Option`]类型 /// `add_one` 返回一个[`Option`]类型
@ -323,7 +323,7 @@ macro_rules! foo {
``` ```
## 文档搜索别名 ## 文档搜索别名
Rust文档支持搜索功能我们可以为自己的类型定义几个别名以实现更好的搜索展现当别名命中时搜索结果会被放在第一位: Rust 文档支持搜索功能,我们可以为自己的类型定义几个别名,以实现更好的搜索展现,当别名命中时,搜索结果会被放在第一位
```rust ```rust
#[doc(alias = "x")] #[doc(alias = "x")]
#[doc(alias = "big")] #[doc(alias = "big")]
@ -333,7 +333,7 @@ pub struct BigX;
pub struct BigY; pub struct BigY;
``` ```
结果如下图所示: 结果如下图所示
<img alt="" src="/img/comment-05.png" class="center" /> <img alt="" src="/img/comment-05.png" class="center" />
@ -341,18 +341,18 @@ pub struct BigY;
这个例子我们将重点应用几个知识点: 这个例子我们将重点应用几个知识点:
- 文档注释 - 文档注释
- 一个项目可以包含两个包:二进制可执行包和`lib`包(库包), 它们的包根分别是`src/main.rs`和`src/lib.rs` - 一个项目可以包含两个包:二进制可执行包和 `lib` 包(库包),它们的包根分别是 `src/main.rs``src/lib.rs`
- 在二进制包中引用 `lib` - 在二进制包中引用 `lib`
- 使用 `pub use` 再导出 API并观察文档 - 使用 `pub use` 再导出 API并观察文档
首先,使用`cargo new art`创建一个package `art`: 首先,使用 `cargo new art` 创建一个Package `art`
```console ```console
Created binary (application) `art` package Created binary (application) `art` package
``` ```
系统提示我们创建了一个二进制`package`,根据[之前章节](./crate-module/crate.md)学过的内容,可以知道该`package`包含一个同名的二进制包:包名为`art`,包根为`src/main.go`,该包可以编译成二进制然后运行。 系统提示我们创建了一个二进制 `Package`,根据[之前章节](./crate-module/crate.md)学过的内容,可以知道该 `Package` 包含一个同名的二进制包:包名为 `art`,包根为 `src/main.rs`,该包可以编译成二进制然后运行。
现在,在`src`目录下创建一个`lib.rs`文件, 同样,根据之前学习的知识,创建该文件等于又创建了一个库类型的包,包名也是`art`,包根为`src/lib.rs`,该包是是库类型的,因此往往作为依赖库被引入。 现在,在 `src` 目录下创建一个 `lib.rs` 文件,同样,根据之前学习的知识,创建该文件等于又创建了一个库类型的包,包名也是 `art`,包根为 `src/lib.rs`,该包是是库类型的,因此往往作为依赖库被引入。
将以下内容添加到 `src/lib.rs` 中: 将以下内容添加到 `src/lib.rs` 中:
```rust ```rust
@ -401,7 +401,7 @@ pub mod utils {
在库包的包根 `src/lib.rs` 下,我们又定义了几个子模块,同时将子模块中的三个项通过 `pub use` 进行了再导出。 在库包的包根 `src/lib.rs` 下,我们又定义了几个子模块,同时将子模块中的三个项通过 `pub use` 进行了再导出。
接着,将下面内容添加到`src/main.rs`中: 接着,将下面内容添加到 `src/main.rs` 中:
```rust ```rust
use art::kinds::PrimaryColor; use art::kinds::PrimaryColor;
use art::utils::mix; use art::utils::mix;
@ -413,12 +413,12 @@ fn main() {
} }
``` ```
在二进制可执行包的包根`src/main.rs`下,我们引入了库包`art`中的模块项,同时使用`main`函数作为程序的入口,该二进制包可以使用`cargo run`运行: 在二进制可执行包的包根 `src/main.rs` 下,我们引入了库包 `art` 中的模块项,同时使用 `main` 函数作为程序的入口,该二进制包可以使用 `cargo run` 运行:
```console ```console
Green Green
``` ```
至此,库包完美提供了用于调色的API, 二进制包引入这些API完美的实现了调色并打印输出。 至此,库包完美提供了用于调色的 API二进制包引入这些API完美的实现了调色并打印输出。
最后,再来看看文档长啥样: 最后,再来看看文档长啥样:

Loading…
Cancel
Save