用 AI 写了一堆看不懂的 Rust 代码,所以做了个工具逼自己看懂
用 Claude Code 写了好几个 Rust 项目,但说实话,99% 的代码都是 AI 生成的,多数时候一扫而过,根本不理解在干什么。今天做的 rust-dojo,本质上是一个逼自己读懂这些代码的工具。
真正的问题
用 AI 辅助写代码,效率很高,但有个副作用:代码跑起来了,但你不知道为什么。
看到一段链式迭代器,大概知道在过滤什么、收集什么,但 .flatten() 为什么在这里?filter_map 和 map + filter 有什么区别?去掉某个方法会发生什么?这些问题平时不会停下来想,因为代码"能跑"。
rustlings 之类的静态题库解决不了这个问题——题目是别人设计的,跟自己项目里的代码完全脱节。做完了对自己写的(或者说 AI 帮写的)那堆代码依然陌生。
所以想法很直接:让 AI 扫我自己的代码库,从里面出题考我。
系统设计
五个模块:
scanner.rs 扫描本地 .rs 文件,按函数/impl 边界切块,记录行号
evaluator.rs 调用 AI API,生成题目 + 评估答案
engine.rs 会话管理,自适应难度(连续 2 次对 → +1★,错 → -1★)
questions.rs 题目数据结构,生成答题文件模板
main.rs 交互主循环
出题逻辑:70% 概率基于扫到的本地代码片段,30% 出通用 Rust 题。每题两部分:
- 读懂代码——围绕片段里某个具体机制提问,不是泛泛问「这段代码做了什么」
- 举一反三——引申出一个经典编程练习,用「另外,请实现…」自然衔接
答题文件长这样:
// 题目 #3 [迭代器与集合操作] 难度: ★★☆☆☆
//
// 节选自 scanner/mod.rs 第17-38行
// fn collect_rs_files(...) { ... }
//
// 为什么这里需要 .flatten()?去掉它会发生什么?
// 另外,请实现一个函数,遍历目录并返回所有 .toml 文件路径。
/* 解释和说明:
*/
fn main() {
}
写完按 Enter,AI 评分并把反馈追加到文件末尾。
几个设计决策
API 统一走 OpenAI 兼容格式
本来想区分 Claude 和 OpenAI 两套,后来发现中转 API 都是 OpenAI 兼容格式,干脆统一走 /v1/chat/completions。key 前缀自动推断默认 base_url:
let default_base_url = if api_key.starts_with("sk-ant-") {
"https://api.anthropic.com"
} else {
"https://api.openai.com"
};
官方 key 用户只需设置一个环境变量,中转用户再加 API_BASE_URL 和 API_MODEL。
未完成题续接
Session 里加了 pending_question: Option<Question>,出题后立刻持久化。重启时检测这个字段——有未完成的题就直接展示,不重新出新题。防止每次 cargo run 都绕过上一道没做的。
中英文双语
lang.rs 统一管理所有 UI 字符串和 AI 提示词,通过 RUST_QUIZ_LANG=en/zh 或系统 locale 自动切换。AI 出题和评估的语言也随之切换。
发布
.gitignore 屏蔽个人数据,scan_dirs.example.txt 作为路径配置模板:
gh repo create rust-dojo --public --source=. --remote=origin --push
https://github.com/Hamiltonxx/rust-dojo
GitHub 上 AI + 自适应 + 基于自己代码库出题这个组合目前是空白。
其实,rust-dojo 本身也是 Claude Code 帮忙生成的。用一个稍微简单点的魔法,帮自己打败另一堆看不懂的魔法,最后内化成自己的魔法!