Storforge
编码预计 40 分钟

Rust 工具链:cargo 就是你的 systemctl

用运维的类比法把 rustup、cargo、clippy、rust-analyzer 一次配齐,建好 forge 项目的 cargo workspace,写下第一个带单元测试的函数。

学完这节你能做到

  • 装好 rustup 工具链并说清 stable/nightly 的关系
  • 用 cargo new / test / clippy / fmt 完成一轮开发循环
  • 建好 forge 的 workspace 骨架:forge-store、forge-proto、forge-cli

cargo 就是你的 systemctl

运维的经验可以直接搬过来:一个生态好不好用,看它的「统一入口」争不争气。 Rust 的答案是 cargo —— 构建、测试、静态检查、格式化、文档、依赖管理全在一个命令下, 就像 systemd 之于服务管理。这也是我们选 Rust 教学的原因之一:工具链没有内耗, AI 生成的代码能被一套标准命令立刻验证。

安装工具链

# rustup:Rust 官方的"工具链版本管理器",类比你管多版本内核/JDK 的方式
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# 装完确认
rustc --version    # 编译器
cargo --version    # 构建工具 + 包管理

几个概念对齐一下:

名字是什么运维类比
rustup工具链版本管理alternatives / 多版本内核共存
rustc编译器,几乎不直接调用你也不直接调 ld
cargo构建/测试/依赖统一入口systemctl + yum 合体
stable / nightly发布通道,六周一版RHEL 正式源 vs epel-testing
crate一个包(库或可执行)一个 rpm 包
crates.io官方包仓库官方 yum 源

本教程全程用 stable,不碰 nightly。

编辑器装 rust-analyzer(VS Code 扩展市场直接搜),悬停显示类型、保存即报错 —— review AI 代码时它是你的第一双眼睛。

一轮开发循环

cargo new hello && cd hello   # 新建项目,自带 git
cargo run                      # 编译 + 运行
cargo test                     # 跑测试
cargo clippy                   # 静态检查:比编译器更严格的"资深同事"
cargo fmt                      # 格式化:终结所有风格争论
✓把 clippy 当导师

clippy 的每条告警都带解释链接,专治「代码能跑但不像 Rust」。 AI 生成的代码全部先过一遍 cargo clippy -- -D warnings(告警当错误), 这是零成本的第一道 review。

建立 forge 仓库

现在正式开工。forge 用 cargo workspace 组织 —— 一个仓库,多个 crate, 统一编译和测试。为什么一开始就分多个 crate?因为它强迫你把接口边界想清楚, 这是后面五个阶段不返工的关键:

forge/
├── Cargo.toml          # workspace 清单
├── crates/
│   ├── forge-util/     # 通用工具:容量解析、校验和…… 今天就写它
│   ├── forge-store/    # L1 的主角:单机存储引擎
│   ├── forge-proto/    # L3 的主角:节点间协议定义
│   └── forge-cli/      # 管理命令行,你最熟悉的那种工具

workspace 根的 Cargo.toml:

[workspace]
resolver = "2"
members = ["crates/*"]

[workspace.package]
edition = "2021"
license = "MIT"

第一个函数:容量解析

上一节的 AI 结对任务如果你做了,现在让 AI 把它搬进 forge-util 正式安家。 搬完大概长这样 —— 这段是给你读的,让你知道「一个带测试的 Rust 模块」是什么形状, 不用你写:

/// 解析人类可读容量:"1.5TiB" -> 字节数。
/// 二进制单位按 1024,十进制单位按 1000;溢出与非法输入返回 Err。
pub fn parse_capacity(s: &str) -> Result<u64, CapacityError> {
    // ... 你和 AI 的实现
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn binary_vs_decimal() {
        assert_eq!(parse_capacity("1KiB").unwrap(), 1024);
        assert_eq!(parse_capacity("1KB").unwrap(), 1000);
    }

    #[test]
    fn overflow_is_error() {
        assert!(parse_capacity("999999999TiB").is_err());
    }
}

读法很简单:上半截是干活的部分,下半截 mod tests 里每个 fn 是一条测试 —— assert_eq! 就是「这两个必须相等」。你能看懂这些断言在断言什么,就够了: review 测试比 review 实现重要得多,因为测试写的是「这个系统承诺了什么」。

为什么第一个函数选它?因为你太熟了 —— 运维时你被 TB/TiB 坑过 (厂商说 20TB,系统显示 18.2TiB,老板问少的去哪了)。熟悉的领域,陌生的语言, 这是转型期选题的黄金法则:领域你说了算,语言交给 AI。

Checkpoint单选

为什么 forge 从第一天起就用 workspace 分多个 crate,而不是先写一个大 crate 后面再拆?

加上 CI:你的地盘你做主

运维人建仓库的本能:先上自动化门禁。.github/workflows/ci.yml:

name: ci
on: [push, pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - run: cargo fmt --check
      - run: cargo clippy --workspace -- -D warnings
      - run: cargo test --workspace

从此 AI 写的每一行代码都要过这三道门 —— 这就是 L0 里程碑的验收标准: workspace 建好,第一个带测试的 crate 在 CI 上全绿。

⚡AI 结对:初始化 forge 仓库pair with ai

这就是 L0 的出口任务。AI 干完后,按上一节的三道关验收 —— 机器关看三道门绿不绿,讲解关让它说清楚四块怎么分的、 为什么这么分,行为关你自己敲命令试 1KiB 和 1KB。 重点盯错误信息那张表:每种错误能不能区分开,是你未来排查问题时唯一的抓手。

目标:建起 forge 项目的骨架,这是一个学习用的分布式存储系统。今天要的是「空架子 + 一个真功能 + 自动化门禁」,后面五个阶段都往这个架子上长。

行为规格:
1. 项目分成四块,边界现在就划清楚:通用工具、单机存储引擎、节点间协议、管理命令行。现在后三块可以是空壳,但目录和依赖关系要立起来;
2. 通用工具那块放上一节的容量解析功能:KiB/MiB/GiB/TiB 按 1024 进位,KB/MB/GB/TB 按 1000 进位,支持小数和一个可选空格;空串、未知单位、大到装不下的数字都要明确报错,不许让程序崩溃;
3. 每种报错要能区分开 —— 我以后排查时得知道到底是「单位不认识」还是「数字太大」,不能全都是一句「解析失败」;
4. 管理命令行先只做一件事:给它一个容量写法,打印出对应的字节数,让我能直接在终端上试;
5. 配一套自动化门禁(GitHub Actions),每次提交自动跑:格式检查、静态检查(告警一律当错误)、全部测试。这三道门从今天守到项目结束。

交付:项目骨架 + 容量解析的实现和测试(覆盖两种进位、小数、空串、未知单位、数字过大)+ CI 配置 + 一条我能在终端直接试的命令。
最后请解释一下:为什么一上来就分成四块,而不是先写成一大坨以后再拆。
你的验收动作自己跑、自己看,不用读代码
  • 让它把三道门(格式、静态检查、测试)在本地各跑一遍,只看全绿还是有红的
  • 推一次到 GitHub,去 Actions 页面看这三道门真的跑起来了 —— 本地绿不算数,门禁绿才算
  • 自己在终端敲那条命令试:1KiB 应该是 1024,1KB 应该是 1000。这两个数一样就说明两套单位混了,当场打回
  • 让它列一张表:每种报错情况分别返回什么信息。然后自己试其中两三种,看实际报错和表里写的对不对得上
  • 让它故意把 CI 里某一道门弄失败(比如塞一段格式不对的代码),推上去确认 Actions 真的会变红 —— 拦不住东西的门禁等于没有
必须问到听懂的问题答不上来就别合并
  • 如果我传一个大到装不下的数字,程序内部是先算出来溢出了、还是算之前就发现不对?这两种做法有什么区别?
  • 这四块之间现在谁依赖谁?以后我想把存储引擎单独拿出去用,会被什么卡住?

小结

  • rustup 管版本,cargo 管一切;全程 stable,clippy 当导师
  • forge 用 workspace 起步,crate 边界就是架构边界
  • 第一个函数选你最熟的领域:容量解析,TB 和 TiB 的旧账新算
  • CI 三道门(fmt/clippy/test)从第一天守到最后一天

延伸资料