Rust 加 AI 学习效率翻倍:把学到的概念马上用 AI 生成练习题验证
一、学习闭环:文档 → 笔记 → 练习 → 验证 → 巩固
传统的学习方式是"看文档 → 看示例 → 以为自己懂了",但这个"以为"往往是错觉。我现在的流程是:
第一步:读文档,做笔记。 用自己的语言复述概念,不是复制粘贴。
比如学完 Rust 的 Deref trait 后,我的笔记长这样:
// 我的笔记:Deref 的作用
// 1. 让智能指针像普通引用一样使用(*ptr 等价于 *ptr.deref())
// 2. 隐式 Deref 强制转换:&Box<String> 可以自动转成 &str
// 3. 注意:Deref 不能反过来(不能从 &str 得到 &Box<String>)
第二步:让 AI 出题。 使用以下 prompt:
"我刚学完 Rust 的 Deref trait,请出 5 道由浅入深的练习题,每道题要考察不同的使用场景。格式要求:
- 题目描述(中文)
- 预期的考察点
- 不给我答案,只给题目
难度从"基础语法"到"实际工程场景"递增。"
AI 给出了这样的题目:
| 题号 | 题目简述 | 考察点 |
|---|---|---|
| 1 | 为自定义结构体实现 Deref,使其可以被解引用 | Deref trait 基本实现 |
| 2 | 写一个函数接受 &str,传 &Box<String> 看能否自动转换 | Deref 强制转换 |
| 3 | 实现一个包装器 MyStr 同时实现 Deref 和 DerefMut | 可变 vs 不可变 Deref |
| 4 | 解释为什么 *x 在不同上下文可能调用不同方法 | 方法解析与 Deref |
| 5 | 设计一个"配置覆盖"结构,用 Deref 实现层叠配置 | 工程场景应用 |
二、写题实践:我的解题代码和 AI 点评
以下是第 3 题的实践过程:
AI 出的题目:
实现一个
MyStr结构体,包装String,实现Deref(不可变借用)和DerefMut(可变借用),然后在代码中演示两者的区别。
我写的代码:
use std::ops::{Deref, DerefMut};
/// 自定义字符串包装器 —— 实践中可能用于添加额外元数据
struct MyStr {
inner: String, // 实际存储的字符串数据
modified_count: u32, // 记录被修改的次数(演示用途)
}
impl MyStr {
fn new(s: &str) -> Self {
Self {
inner: s.to_string(),
modified_count: 0,
}
}
/// 获取修改次数 —— 通过 Deref 只能访问 inner,不能访问这个字段
fn modification_count(&self) -> u32 {
self.modified_count
}
}
// 实现不可变解引用:&MyStr → &String → &str
impl Deref for MyStr {
type Target = String; // 指定解引用后的目标类型
fn deref(&self) -> &Self::Target {
&self.inner // 返回内部 String 的引用
}
}
// 实现可变解引用:&mut MyStr → &mut String
impl DerefMut for MyStr {
fn deref_mut(&mut self) -> &mut Self::Target {
self.modified_count += 1; // 记录修改次数
&mut self.inner // 返回内部 String 的可变引用
}
}
fn main() {
let mut my = MyStr::new("hello");
// 测试 1:不可变 Deref —— 可以调用 String 的方法
// str_len 的类型是 &String,但可以自动解引用为 &str
let str_len = my.len(); // 实际调用 my.deref().len()
println!("长度: {}", str_len);
// 测试 2:可变 DerefMut —— 可以调用 String 的 mut 方法
my.push_str(" world!"); // 实际调用 my.deref_mut().push_str(...)
println!("修改后: {}", my.deref()); // 打印 "hello world!"
println!("修改次数: {}", my.modification_count()); // 输出: 1
// 测试 3:Deref 强制转换
fn takes_str(s: &str) {
println!("收到 &str: {}", s);
}
takes_str(&my); // &MyStr 自动 Deref 为 &String,再 Deref 为 &str
}
AI 的点评:
整体实现正确,
Deref/DerefMut的核心逻辑没问题。几点改进建议:
Deref的Target设为String没问题,但实践中更常见的是设为str(直接解引用为字符串切片,减少一层间接访问)。可以试试把Target改为str,看看deref方法需要怎么改。- 你在
deref_mut里加了modified_count += 1这个副作用,这个设计在实际项目中要注意:DerefMut 应该是透明的,不推荐在解引用时产生副作用,因为这会让代码行为变得难以预测。建议把修改计数放到专门的 setter 方法里。- 可以补充一个测试:当
MyStr被不可变借用时(&my),能否调用push_str?为什么?
我的心得:AI 的点评帮我发现了一个我自己意识不到的问题——在设计 trait 实现时引入副作用。这种"隐性知识"是靠看书很难获得的,需要有人指出才能意识到。
三、练习题的分类和设计原则
经过几十次这样的练习,我发现 AI 出题的质量很大程度上取决于你的 prompt。好的 prompt 需要明确:
/// 我的"AI 出题请求"模板
fn build_exercise_prompt(topic: &str, difficulty_areas: &[&str]) -> String {
format!(
"我刚学完 Rust 的「{topic}」,请出 4 道练习题。
要求:
1. 难度梯度:基础语法 → 常见陷阱 → 实际工程场景 → 与其他概念的交叉
2. 每道题标注考察的特定能力:{areas}
3. 工程场景要真实(比如"写一个 HTTP 请求解析器用到了 X")
4. 不要给答案
请用你实际遇到过的问题来启发题目设计。",
topic = topic,
areas = difficulty_areas.join("、"),
)
}
// 使用示例
let prompt = build_exercise_prompt(
"生命周期标注",
&["函数签名标注", "结构体生命周期", "协变逆变", "更高阶生命周期"],
);
我总结的有效的练习梯度:
四、学习效率的实测对比
为了验证这套方法的效果,我用同样的时间(每天 2 小时,持续 1 周),对比了纯看书和我这种方法在"Rust 的 async/await 和 Future 概念"上的学习效果:
| 对比维度 | 纯看书+看博客 | 看书+AI 出题练习 |
|---|---|---|
| 看完资料的时间 | 3 天 | 2 天 |
| 练习题完成量 | 0(没找到合适的题) | 15 题 |
| 能独立写出异步代码 | 第 5 天 | 第 3 天 |
| 遇到编译错误的平均解决时间 | 15 分钟 | 5 分钟 |
| 一周后概念遗忘率 | 约 40% | 约 15% |
最关键的区别是:被动阅读的知识留存率远低于主动练习。AI 生成练习题让我在学完的 10 分钟内就开始主动输出,而不是被动接收。
五、总结
这套方法的核心就三点:
- 用自己的话复述——不做笔记的学习等于没学。
- 让 AI 出题,不给答案——AI 是出题工具,不是抄答案的工具。自己动手做,比看 AI 写的答案有效 10 倍。
- 把自己的代码发给 AI 点评——AI 能发现你自己意识不到的问题(比如编码风格、边界条件、工程实践)。
作为程序员,我知道自己在基础理论上有短板。但这些短板不是不可弥补的——关键是有没有一套高效的学习方法。AI 帮不了你理解概念(那是你自己的事),但它可以帮你加速"学习 → 练习 → 验证"这个闭环,而这个闭环,才是编程学习的本质。
希望这套方法对同样在自学 Rust 的朋友有帮助。一起加油。

716

被折叠的 条评论
为什么被折叠?



