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 的每条告警都带解释链接,专治「代码能跑但不像 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 结对任务如果你做了,现在把它搬进 forge-util,签名转正:
/// 解析人类可读容量:"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());
}
}
为什么第一个函数选它?因为你太熟了 —— 运维时你被 TB/TiB 坑过 (厂商说 20TB,系统显示 18.2TiB,老板问少的去哪了)。熟悉的领域,陌生的语言, 这是转型期选题的黄金法则。
为什么 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 上全绿。
这就是 L0 的出口任务。AI 干完后,按上一节的三道关 review:
重点读 CapacityError 的定义(每种错误是否可区分?)和溢出测试
(它用的乘法会不会先 panic 再返回 Err?搜一下 checked_mul)。
帮我初始化一个叫 forge 的 Rust cargo workspace,这是一个学习用的分布式存储系统项目: 1. workspace 含 4 个成员:crates/forge-util(lib)、crates/forge-store(lib)、crates/forge-proto(lib)、crates/forge-cli(bin); 2. workspace 级统一 edition = "2021",resolver = "2"; 3. forge-util 里实现 parse_capacity(s: &str) -> Result<u64, CapacityError>,规格:KiB/MiB/GiB/TiB 按 1024,KB/MB/GB/TB 按 1000,支持小数和可选空格,溢出返回 Err 不 panic,CapacityError 用 thiserror 定义; 4. 附完整单元测试,覆盖:两种进位、小数、空串、未知单位、溢出; 5. 加 GitHub Actions CI:fmt --check、clippy -D warnings、test; 6. forge-cli 先只做一件事:forge-cli parse <SIZE> 打印解析出的字节数。 完成后依次运行 cargo fmt --check、cargo clippy --workspace -- -D warnings、cargo test --workspace,贴出结果。
小结
- rustup 管版本,cargo 管一切;全程 stable,clippy 当导师
- forge 用 workspace 起步,crate 边界就是架构边界
- 第一个函数选你最熟的领域:容量解析,TB 和 TiB 的旧账新算
- CI 三道门(fmt/clippy/test)从第一天守到最后一天