新闻详情

新闻详情

首页 / 资讯中心 / 详情

用 AI 学编程的最大误区:不是让 AI 代写代码,而是让 AI 教你理解代码

发布时间:2026/7/28 15:06:50
用 AI 学编程的最大误区:不是让 AI 代写代码,而是让 AI 教你理解代码
用 AI 学编程的最大误区不是让 AI 代写代码而是让 AI 教你理解代码一、一个让我后背发凉的 GitHub 对话上个月我在一个 Rust 学习群里看到一段对话。一个刚学 Rust 两周的新人贴了一段代码问为什么cargo check报错cannot borrow as mutable。群里有人回把这一行改成let mut x x.clone();就行了。新人改了编译通过发了个谢谢的表情。五分钟后他又贴了一段几乎一模一样的代码同样的问题。这不是孤例。群里每天都在发生同样的事有人给了能编译的改法没人解释背后的原因。而 ChatGPT 加剧了这个问题。因为它永远能给出能跑的代码。一个初学者用 5 秒钟复制粘贴的解决方案可能掩盖了一个需要花 2 小时才能真正理解的底层概念。这就是我这篇文章想说的核心矛盾你用 AI 学编程的姿势决定了你是在学编程还是在对 AI 产生不可逆的依赖。二、错误的 AI 学习路径左边是大多数人的做法右边是少数人的做法。两条路径的最终结果天差地别。三、AI 用法的层次与五步学习法层次 1AI 当搜索引擎 —— 最浪费用户Rust 怎么读文件 AI 用 std::fs::read_to_string……你获得了一段代码但没有获得理解。下次你遇到读大文件或者读二进制文件你还是不会。层次 2AI 当代码生成器 —— 最危险用户帮我写一个和多线程安全的缓存 AI [生成含 ArcMutexHashMap 的代码]你获得了一个能跑的解决方案但你不知道为什么用Arc而不仅仅是Rc不知道为什么Mutex和RwLock的选择取决于读写比例。下一次你换一个场景——比如需要跨tokio::spawn共享这个缓存——你就卡住了。层次 3AI 当导师 —— 正确用法用户我在学 Rust 的所有权。我写了一段代码想用一个 Vec 存储一些 String然后在两个地方同时使用它。编译器报错了。 [粘贴代码和错误信息] *不要给我现成的解决方案代码。* 请帮我 1. 解释为什么编译器不允许这样做 2. 描述三种不同的解决方法以及每种方法的 trade-off 3. 画出内存布局图让我直观理解 AI 好我来逐层分析 1. 为什么编译不过 因为你把 Vec 的所有权 move 进了第一个使用者。 在 Rust 里一个值只能有一个所有者。你已经把所有权 交出去了第二个人就借不到了。 2. 三种方案及 trade-off 方案 Aclone() - 把整个 Vec 复制一份给第二个人 - 优点简单两个副本各自独立 - 缺点内存翻倍大 Vec 时不可接受 方案 B引用 Vec - 两个人都不获取所有权只借用 - 优点零内存开销 - 缺点必须确保借用期间原数据不被释放 方案 CArc (共享所有权) - 包装在 Arc 里多个人共享同一个数据 - 优点没有借用检查的麻烦 - 缺点引用计数开销不可变的共享 3. 内存布局图 [用 ASCII 或 Mermaid 画出每种方案的内存布局]看到区别了吗你不再是被动接收代码而是在和 AI 进行概念层面的对话。AI 辅助学习的五步法这是我自己梳理出的学习流程。每学一个新概念我都按这个顺序来第一步自己先写写出问题千万别在白纸上让 AI 写代码。一定要自己先尝试。/// 你在学 async Rust。自己先写一个你觉得应该可以跑的版本 #[tokio::main] async fn main() { let mut data vec![1, 2, 3]; // 你感觉这样应该可以并发处理 let handle1 tokio::spawn(async { data.push(4); // 修改 data }); let handle2 tokio::spawn(async { println!({}, data.len()); // 读取 data }); // 编译器error[E0373]: closure may outlive the current function, // but it borrows data, which is owned by the current function }现在你有了一个具体的问题而不是一个泛泛的教我用 async。第二步问为什么不问怎么做用户上面的代码为什么编译不过我需要理解编译器说的 borrows data, which is owned by the current function 到底是什么意思。请用内存模型的角度解释。这一步的关键是你的 prompt 里不能出现帮我写三个字。第三步限制 AI 作答 —— 不给代码用户请用以下格式回答 1. 为什么 data 不能被两个 task 共享所有权视角 2. 如果我想让两个 task 都能访问 data有几种思路 3. 每种思路的内存布局有什么不同用文本图表示 4. 每种思路的性能影响是什么 *不要给我代码解决方案。*这一步在逼迫 AI 当老师而不是自动补全。同时你在培养一种习惯先理解原理再看实现。第四步自己写让 AI 审/// 你自己根据理解写出的代码 use std::sync::Arc; use tokio::sync::Mutex; #[tokio::main] async fn main() { let data Arc::new(Mutex::new(vec![1, 2, 3])); let data_clone data.clone(); let handle1 tokio::spawn(async move { let mut guard data_clone.lock().await; guard.push(4); }); let data_clone2 data.clone(); let handle2 tokio::spawn(async move { let guard data_clone2.lock().await; println!(长度: {}, guard.len()); }); let _ tokio::join!(handle1, handle2); } // 然后问 AI // 这段代码有什么我没有考虑到的隐患吗提示锁的粒度。 // // AI 可能会指出 // handle2 在持有锁的时候执行 println! —— 如果打印操作很慢 // handle1 会一直被阻塞。应该先 drop guard 再打印。第五步输出 —— 教会别人教会自己我在 CSDN 写博客的最初原因不是为了流量而是为了检验自己是否真的理解了。如果你不能把一件事解释给一个外行听你就没有真正理解它。/// 你学到的是概念不只是语法 /// /// 1. tokio::spawn 要求闭包是 static → 需要 move /// 2. 多 task 共享可变数据 → ArcMutexT /// 3. 锁的粒度问题 → 尽量缩短持有锁的时间 /// 4. tokio::sync::Mutex vs std::sync::Mutex → /// 异步上下文用 tokio 版本避免跨 .await 持有标准锁四、核心竞争力与自学建议现在人人都会用 AI 写代码。那什么才是区分水平的关键AI 能生成代码但不能替代你做这三件事辨别力AI 说在 HashMap 外包 Mutex但你知道 Reads 远多于 Writes应该用 RwLock。这个判断来自你对读写比例这个场景参数的理解不是来自代码。理解力AI 生成的代码你能逐行解释它为什么这样写吗如果不能它就不是你的代码——它是 AI 的代码暂时寄存在你的仓库里。设计力AI 能帮你实现一个功能但不能帮你决定这个功能该不该做。你的项目的整体架构、技术选型、开发优先级——这些是 AI 的训练数据里没有的上下文。我给自学者的五条建议建议 1每天有一段无 AI 时间每天给自己 30 分钟关掉 AI只靠文档和编译器写代码。这 30 分钟在培养的是你的独立思考肌肉。建议 2用 AI 生成解释但自己写代码我现在的 prompt 模板我在学 [概念]。请用三个不同的比喻帮我理解它。 每个比喻对应不同层次的理解 - 给刚学编程的人 - 给有其他语言经验的人 - 给已经理解但想深入的人 不要给我代码。建议 3用 AI 审代码不是写代码把你的代码给 AI问它有哪些我没有考虑的边界情况这段代码在高并发的场景下会有什么问题如果能改一个地方你会改哪里为什么建议 4问问题比要代码有效 10 倍要代码的 prompt要理解的 prompt帮我写一个 WebSocket 客户端WebSocket 和 HTTP 长轮询的本质区别是什么在什么场景下长轮询反而是更好的选择这个 bug 怎么修这个 bug 的根因是什么是不是还有类似的地方可能存在同样的问题建议 5建立我独立完成的里程碑每个月或每两周挑一个任务完全不用 AI。从头到尾靠自己查文档、看源码、调试。这个任务不需要大——写一个命令行参数解析器、实现一个简单的 LRU 缓存——但它必须是你独立完成的。这些独立完成的时刻才是你真正在成长的时候。实操案例用 AI 导师法学 Rust 的生命周期——我的完整过程去年 8 月我遇到了学习 Rust 以来最大的坎生命周期标注。不是简单的fn fooa(x: a str)那种——而是为什么tokio::spawn要求static、为什么 struct 里不能自引用、async fn 里的生命周期到底怎么回事这类绕不明白的问题。我没有像一开始那样让 ChatGPT 给出把生命周期改成static就行了的回答。我按着五步法来第一步自己先写我写了一个简单的任务调度器想在struct Scheduler里存一个对Config的引用然后在tokio::spawn里使用它。编译器报了 7 行错我全部保留了下来。第二步问为什么我把代码和完整编译错误贴给 AIprompt 是请从内存模型角度解释为什么 spawn 需要 static如果 Config 在整个程序运行期间都不会被释放为什么编译器还是不让我这么做不要给我改好的代码。第三步限制作答AI 解释了static不是活到程序结束而是在任意时刻都可以安全访问——tokio::spawn不知道 Config 什么时候会被 drop所以要求闭包内所有引用都必须满足static。同时解释了 Rust 的生命周期是编译期的保守检查即使你知道 Config 会一直活着编译器不知道——它只看类型签名。第四步自己写让 AI 审我理解后用ArcConfig把所有权共享出去重写了调度器。然后问 AI我的实现有内存泄漏吗如果 Config.workers 是 0 会怎样如果 tokio runtime 在 Config 创建之前就 shutdown 了会怎样出来 3 个边界 bug。第五步输出博客花了 2 小时把那天的学习过程写成了一篇博客tokio::spawn 的 static 到底是什么意思——后来成了我 CSDN 阅读量最高的文章之一。整个过程比复制粘贴能跑的代码多花 3 倍时间但从此以后static、Arc、tokio::spawn这三个概念在我的脑子里是连在一起的而不是孤立的语法点。这就是我理解的AI 当导师——它帮你理解为什么而你负责把理解内化。五、总结写这篇文章的时候我翻了一下 GitHub Copilot 的使用统计过去三个月它提供了 43% 的代码建议我接受了其中 27%。这 27% 里有多少是理解之后的选择有多少是图省事的复制粘贴我诚实地说差不多对半分。自学出身让我对理解有天然的执念。因为我知道如果我对一个概念没有彻底的理解下一次面试官或者线上 bug 就会用它来打我脸。而 AI 恰恰是那种让你感觉懂了但其实没懂的工具——就像你看了十分钟教学视频觉得学会了游泳下水之后才发现手脚不协调。用 AI 学编程没有错。错的是把 AI 当成知识来源而不是理解催化剂。AI 应该是一面镜子让你看到自己的理解有多薄弱。它不该是一堵墙挡在你和真正的知识之间。下周预告Week 6 —— 性能优化专题。从 profiling 到瓶颈分析从 Rust 的零成本抽象到底层优化八篇纯技术干货。
网站建设 高端定制 企业官网