综合练习
CLI + JSON API 小项目与 cargo test。
综合练习
这一课你将能做到
- 把前 11 课的知识拼装成一个可运行的迷你判题服务(模型、trait、并发、错误处理)
- 掌握「先顺序跑通、再并发改造」的工程节奏,看懂每一次改造引发的编译器反馈
- 知道从本地玩具到生产判题系统之间还差哪几块(沙箱、持久化、限流)
为什么要学
单知识点听懂了,拼起来还是会手生——move 和生命周期在真实调用链里怎么配合、trait 对象和通道怎么协作,只有完整写过一遍才知道。这个迷你判题服务刻意覆盖本课程全部主线:struct/enum 建模、Result 错误处理、trait 抽象、线程并发、通道回收,最后给出接入 axum 的升级路线。
它也是面试的完美素材:判题服务是「高性能后端」的浓缩案例,隔离、并发、幂等三个经典系统设计题都能从它出发。
先建立图像
mini-judge 数据流:
提交列表 Vec<Submission>
│ 逐个分发(所有权转移)
▼
N 个工作线程 ──沙箱模拟──→ Checker trait 判定 → Verdict
│ │
└────── mpsc 通道发送 (id, verdict) ──────┘
│
主线程 rx 回收 → HashMap<u64, Verdict> → 统计输出
知识点落位对照:
| 项目部件 | 来源课程 |
|---|---|
| Submission / Verdict 建模 | 第 5 课 struct 与 enum |
| Display 输出 | 第 7 课实现标准 trait |
| Checker trait | 第 7 课 trait 抽象 |
| 并发编排 + 通道 | 第 9 课 thread 与 mpsc |
| main 返回 Result | 第 6 课错误处理 |
跟着做
步骤 1:建项目,写数据模型
cargo new mini-judge
cd mini-judge
src/main.rs 开头:
use std::collections::HashMap;
use std::fmt;
use std::sync::mpsc;
use std::thread;
#[derive(Debug, Clone)]
struct Submission {
id: u64,
problem: String,
code: String,
}
#[derive(Debug, Clone, PartialEq)]
enum Verdict {
Accepted { time_ms: u32 },
WrongAnswer,
CompileError(String),
}
impl fmt::Display for Verdict {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Verdict::Accepted { time_ms } => write!(f, "AC({time_ms} ms)"),
Verdict::WrongAnswer => write!(f, "WA"),
Verdict::CompileError(e) => write!(f, "CE:{e}"),
}
}
}
Verdict 用 enum 而不是 bool:AC/WA/CE 是状态机,未来加 TLE/RE 只需加变体,match 的穷尽性会逼着所有处理点同步更新。
步骤 2:Checker trait 与实现
trait Checker {
fn check(&self, output: &str, expect: &str) -> Verdict;
fn name(&self) -> &str { "checker" } // 默认实现
}
struct ExactChecker;
impl Checker for ExactChecker {
fn check(&self, output: &str, expect: &str) -> Verdict {
if output.trim() == expect.trim() {
Verdict::Accepted { time_ms: 3 } // 真实系统由沙箱计时
} else {
Verdict::WrongAnswer
}
}
fn name(&self) -> &str { "exact" }
}