跳转至

开发辅助工具

本章节将介绍 Rust 生态中一些有用的工具,这些工具可以帮助你在开发过程中提高代码质量、效率和可维护性。

常见工具

Rust 提供了一系列内置工具,帮助开发者在提高开发效率的同时,也能编写高质量、规范的代码。正确使用这些工具,可以让你更加专注于代码的逻辑,而不会被琐碎的细节所困扰。

rustc

Rust 编译器(rustc)不仅能够完成编译功能。相比于 gcc 等编译器来说,它的一个重要优势即是友好的错误提示。对于 Rust 新手来说,编译器的错误提示可以帮助你快速定位问题,从而方便你更快写出正确的代码。

如果代码存在错误或者需要警告的内容,rustc 会输出详细的信息。示例代码如下:

// main.rs
fn main() {
    let x = 42;
    x = x + 1;
    println!("{}", x);
}

我们使用 rustc 编译上述代码:

rustc main.rs

终端会输出如下结果(当前 rustc 版本为 1.85.0-stable):

error[E0384]: cannot assign twice to immutable variable `x`
 --> main.rs:3:5
  |
2 |     let x = 42;
  |         - first assignment to `x`
3 |     x = x + 1;
  |     ^^^^^^^^^ cannot assign twice to immutable variable
  |
help: consider making this binding mutable
  |
2 |     let mut x = 42;
  |         +++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0384`.

上述输出结果可以分为三部分:

  1. 异常原因说明:

    error[E0384]: cannot assign twice to immutable variable `x`
    

    这里 E0384 是错误码,表示 cannot assign twice to immutable variable,即不能对不可变变量进行二次赋值。

      --> main.rs:3:5
      |
    2 |     let x = 42;
      |         - first assignment to `x`
    3 |     x = x + 1;
      |     ^^^^^^^^^ cannot assign twice to immutable variable
      |
    

    这里描述了错误发生的位置和具体的原因: - main.rs:3:5 表示错误发生在 main.rs 文件的第 3 行第 5 列。 - first assignment to x 表示 x 的第一次赋值发生在第 2 行。 - x = x + 1 下的波浪线(若你的终端支持颜色输出,可以看到这是一条红色波浪线)表示错误发生的位置,这里 x 被重复赋值,从而违背了 Rust 的不可变性原则。

  2. 改进建议:

    help: consider making this binding mutable
      |
    2 |     let mut x = 42;
      |         +++
    

    这里给出了一个改进建议,即在 let 关键字后面添加 mut 关键字,从而将 x 声明为可变变量。

  3. 深入信息:

    对于 Rust 编译器发出的错误,编译器会提供一个错误码,并给出一些可能的解释。对上述的错误,编译器给出的错误码是 E0384

    For more information about this error, try `rustc --explain E0384`.
    

    我们可以在终端执行它给出的指令 rustc --explain E0384,从而获取更多关于该错误的信息。更多 rustc 可能给出的错误码详见 Error Code Index

基于 rustc 的建议,我们修改代码之后重新编译,即可得到正确的结果。

自动修复功能

VSCode 等现代 IDE 提供了智能修复功能,可以在编译器报错时根据其给出的建议自动修复代码。我们以上述代码为例,在 VSCode 中写入该段代码,会出现红色波浪线报错。将光标移动到红色波浪线上,会显示出具体的报错内容,如下图:

rustc-error

我们点击 快速修复 按钮,VSCode 会按照编译期的报错,显示如下的修复建议选项。

rustc-fix

其中的 Copilot 选项来自于 VSCode 的 Copilot 插件,详见将 AI 集成到 IDE。我们选择第一项:Change it to be mutable(将其声明为可变变量) 选项,IDE 会自动修正代码的 bug,使其通过编译。

rustc-fix-result

需要注意的是,IDE 的自动修复功能仅是辅助功能,其给出的修复建议可能并不一定正确。因此,当 IDE 无法解决问题时,我们仍然需要仔细阅读编译器的报错信息,并思考解决的方法。

clippy

clippy 是 Rust 官方提供的静态代码分析工具,可以帮助你发现代码中的潜在问题和改进建议,从而让你的代码更加规范、健壮。

为了使用 clippy,你需要先安装 clippy 组件:

rustup component add clippy

示例代码如下:

// src/main.rs
fn main() {
    let x = true;
    if x == true {
        println!("x is true");
    }
}

项目根目录下运行 cargo clippy 后输出:

warning: equality checks against true are unnecessary
 --> src/main.rs:3:8
  |
3 |     if x == true {
  |        ^^^^^^^^^ help: try simplifying it as shown: `x`
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
  = note: `#[warn(clippy::bool_comparison)]` on by default

同样的,我们拆分一下 clippy 的输出结果:

  1. 警告信息与改进建议:

    warning: equality checks against true are unnecessary
     --> src/main.rs:3:8
      |
    3 |     if x == true {
      |        ^^^^^^^^^ help: try simplifying it as shown: `x`
      |   
    

    这里 warning: equality checks against true are unnecessary 代表某个判断相等语句是冗余的。

    在我们的程序中,clippy 认为 if x == true 是冗余的,可以简化为 if x。而 help: try simplifying it as shown: x 给出了改进建议,即简化为 if x

  2. 深入信息:

    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
    = note: `#[warn(clippy::bool_comparison)]` on by default
    

    这里给出了进一步的信息,说明当前的检查属于 clippy::bool_comparison,可以访问 clippy-docs 获取更多信息。

可以使用 #[allow(...)] 属性来禁用特定的检查,屏蔽警告。但是,除非额外启用了一些非常严格的检查规则,默认的规则基本上总是应当遵守的,如果没有非常充分的理由,不应该随意禁用检查。如果你不理解 clippy 提示警告的原因,不知道应该如何修复,可以阅读 help: 中链接的文档,也可以向 AI 和助教求助。

集成 clippy 到 IDE

如果你使用 VSCode 及其衍生的编辑器进行开发,还可以将 clippy 集成到 IDE 的自动检查中和修复中,从而避免了手动调用的麻烦。我们以 VSCode 的 rust-analyzer 插件为例:

  1. 打开命令面板 (快捷键为 Ctrl+Shift+P / Cmd+Shift+P)

  2. 键入 Preferences: Open Settings (JSON),从而打开 settings.json 文件。

  3. 在 settings.json 中加入:

    {
        // Default command is `cargo check`
        "rust-analyzer.check.command": "clippy",
    }
    

上文中,我们设置 rust-analyzer 的检查命令为 clippy。当我们启用了 rust-analyzer 的 checkOnSave 功能(默认是启用的,可以在设置中查找)之后,每次保存文件时,都会自动调用 rust-analyzer.check 命令,从而调用 clippy 实现自动检查。

rustfmt

rustfmt 也是 Rust 官方提供的代码格式化工具,可以帮助你保持代码风格一致。

为了使用 rustfmt,你需要先安装 rustfmt 组件:

rustup component add rustfmt

我们提供一个未格式化的示例代码:

// src/main.rs
fn main(){println!("hello");}

可以看到,代码的格式并不美观。当我们执行如下指令:

rustfmt src/main.rs

可以看到,源文件的代码格式得到了改善。

// src/main.rs
fn main() {
    println!("hello");
}

当我们使用 cargo 管理项目时,也可以通过 cargo fmt 来执行代码格式化,此时本质上仍然是调用了 rustfmt。

rustfmt 的格式化规范是可配置的,默认格式详见 The Default Rust Style。自定义配置的方法和更多选项详见 rustfmt docs

自动格式化

当我们使用 VSCode 等现代 IDE 开发时,可以借助 IDE 的自动格式化功能,在保存代码时自动调用 rustfmt 进行格式化,从而避免了手动调用指令的麻烦。

以 VSCode 为例,配置自动格式化的步骤如下:

  1. 保证 Rust-analyzer 插件和 rustfmt 组件均已安装

  2. 打开设置面板(左下角的齿轮图标)

  3. 搜索 format on save,并勾选

    format on save

此时在编辑完 Rust 代码之后保存(快捷键一般为 Ctrl+S / Cmd+S),即可自动调用对应的格式化工具。对于 rust-analyzer 来说,默认调用 rustfmt 进行格式化。

这些工具可以帮助你在开发过程中及时发现问题、保持代码整洁,提高开发效率。

扩展工具

除去上述提到的常见工具,Rust 生态中来自官方或者第三方维护者的更多工具。这些工具可以帮助你发现代码中的潜在问题和改进建议,从而让你的代码更加规范、健壮。但它们的安装和使用相对复杂,且需要一定的学习成本,因此本章节仅介绍其基本信息。感兴趣的同学可以进一步了解。

工具类别 子类别 工具 重要程度 来源 说明
程序分析工具
👉 静态检查工具
clippy ⭐⭐⭐ clippy 捕获常见的编码错误,并使代码更加地道
mirai ⭐⭐ 论文 检查 panic;支持属性标注
rapx ⭐⭐ RAPx book 检查 UAF 和内存泄露
lockbud ⭐⭐ 论文 检查 deadlock 等并发问题
atomvchecker ⭐⭐ 论文 检查 memory ordering misuse
rudra ⭐⭐ 论文 检查 panic safety 和 Send/Sync Variance
👉 动态检查工具
测试 ⭐⭐⭐ cargo-test 单元测试或集成测试等
miri ⭐⭐⭐ cargo-miri 最高质量的 UB 检查结果
辅助检查工具
👉 格式化检查 fmt ⭐⭐⭐ [rustfmt] 检查未格式化的代码
👉 供应链审查
audit ⭐⭐⭐ cargo-audit 检查是否存在已报告安全漏洞的依赖版本
udeps ⭐⭐ 尽可能消除无用的依赖
outdated 尽可能使用最新的依赖
👉 代码统计 geiger 尽可能警惕不安全代码
👉 版本语义检查 semver ⭐⭐ semver crate 一个严肃的发版应该遵循语义化版本控制

AI 辅助开发

近些年来 AI 辅助开发工具已经逐渐成熟,并开始在开发过程中发挥重要作用。我们将介绍一些可用的 AI 工具,并介绍如何使用它们来辅助开发。

与 Chatbot 交互

近年来,Chatbot 已经逐渐成为开发者的得力助手。通过与 Chatbot 交互,开发者可以快速获取信息、解决问题,从而提高开发效率。

国内 Chatbot 的使用门槛较低,方便同学们快速上手使用,其包括:

对于有兴趣的同学,还可以尝试使用国外一些较为知名的 Chatbot,包括:

国外的 Chatbot 常需要使用特殊手段进行访问、注册,同学们可以自行搜索相关方法。

你可以通过和 Chatbot 交互来解决自己的知识困惑,或协助完成一些调试任务。在本课程中,可被允许使用 Chatbot 的场景详见使用原则

将 AI 集成到 IDE

IDE 全称为 Integrated development environment(集成开发环境),是一种辅助程序开发人员开发软件的应用软件。它通常集成了多个功能组件,比如:

  • 代码编辑器(Code Editor)

  • 调试器(Debugger)

  • 自动补全 / 语法高亮 / 重构工具

  • 项目资源管理器(Project Explorer)

你可以把 IDE 理解为开发者的工具台:所有工具都在一个地方,可以直接编译运行、排查 bug、搜索符号、自动补全等。值得强调的是,对于不同的开发需求(如不同编程语言、图形化等),可能会有不同的适配 IDE。本课程建议大家使用 VSCode 进行开发,在大家熟悉 VSCode 后,可以尝试使用其他 IDE,如 XCode、JetBrains 系列等。

将 AI 集成到 IDE 中,可以显著提高开发效率。例如,在 VSCode 中可以安装 Github Copilot 等插件,从而达到生成注释、补全代码等目的。你可以在 VSCode 的扩展商店中输入 Copilot 进行搜索,并安装对应的扩展。安装完成之后,你可以尝试使用 Copilot 的代码补全功能。下图是一个示例。

Copilot-Completion

在上图示例中,我们在第 4 行给出了对 a 和 b 运算的目标(即计算 a 和 b 的和),此时 Copilot 会以灰体的形式给出一个代码补全的建议,我们可以按下 Tab 按键以接受这个建议,此时代码会自动补全为:

fn main() {
    let a = 1;
    let b = 2;
    // 计算 a 和 b 的和
    let sum = a + b;
}

Github Copilot 学生身份激活

Github Copilot 需要付费使用,但我们可以申请以学生身份免费访问 Copilot Pro,详见以学生、教师或维护者身份免费访问 Copilot Pro

使用原则

AI 的功能很强大,但是我们不能完全依赖 AI 来完成开发。我们使用 AI 工具的原则是:课程作业的主体必须由学生本人独立完成,AI 仅可用于辅助开发,不可直接生成或抄袭作业的核心内容。人性是经不住考验的,所以不要考验自己。如果你觉得自己不能拒绝诱惑,那就不要用 AI。

在本课程中,我们允许使用 AI 的场景包括:

  • 代码片段补全:在编写代码时,可以用 AI 辅助完成简单的代码补全,如意义相近的分支判断、循环结构等。如下列分支代码可以通过 AI 辅助完成补全:

    fn to_english(n: &str) -> &str {
      // 将 1 到 10 的数字转化为英文
      match n {
          "1" => "one",
          "2" => "two",
          "3" => "three",
          // ...
          _ => "unknown",
      }
    }
    
    AI 可以快速补全从 4 到 10 的剩余分支内容,从而提高开发效率。

  • 格式化文档:可被 AI 规范化的文档包括代码注释、项目报告等,AI 可以帮助格式化文档,从而使其更加规范、易读。

  • 辅助调试:如将报错信息和对应源码发送给 AI,让 AI 帮助你分析问题所在,从而协助找出问题。

  • 询问思路:对于某个具体实现问题,可以询问 AI 一些关于实现思路的问题,但是不要让 AI 直接生成代码。

需要注意的是,AI 提供的答案不一定是正确的。如果 AI 的回答有所帮助,需要在代码或 HONOR CODE 中明确注明,从而让课程组了解实际情况。

如何注明对 AI 的使用情况

在代码中:

// Inspired from ChatGPT:
// <answer from ChatGPT>

在 HONOR CODE 中:

关于 <problem>,我向 ChatGPT 提问了 <question>,ChatGPT 回答了 <answer>,启发了我在 <code> 中的实现。

样例:

关于如何重构 Rust 项目的问题,我向 ChatGPT 提问了:在 Rust 里面,如果我想让多个二进制程序共用一部分代码,我该怎么做?

ChatGPT 回答了:

    在 Rust 中,如果你想让多个二进制程序共用一部分代码,可以使用 Rust 的模块系统。

    首先,将你希望共用的代码放到单独的 Rust 模块中,可以是一个单独的源文件或一个子目录。创建一个名为 `lib.rs` 的文件,这个文件必须包含一个名为 `mod` 的声明,指向你的模块代码的文件或目录:

    ```
    // src/my_shared_code/lib.rs

    mod my_module {
        // 公共代码
    }
    ```

    然后,在你的二进制程序的 `Cargo.toml` 文件中,添加一个依赖项,指向你的共享代码模块:

    ```
    [dependencies]
    my_shared_code = { path = "./path/to/my_shared_code" }
    ```

    最后,在你的二进制程序的代码中,使用 `use` 语句导入你的共享代码:

    ```
    // src/my_binary.rs

    use my_shared_code::my_module;

    fn main() {
        // 使用共享代码
    }
    ```

    这样你的二进制程序就可以使用共享代码模块中的代码了。你还可以在其他二进制程序中重复使用同一共享代码模块。

这启发了我的作业的代码组织方式。

以下内容是不被允许的:

  • 直接使用 AI 生成作业主体代码:如将作业要求直接输入给 AI,让 AI 给出对应代码。

  • 使用 AI 翻译、伪原创已有内容,使其看似原创,从而逃避抄袭检测。

  • 使用 AI 生成整篇实验报告,并未经过学生充分理解和改写。

若在核查过程中发现了课程组不允许的行为,将可能以抄袭行为处理,详见抄袭与查重