编程基础篇 · 线性结构:你天天在用

栈:Cmd+Z 和「爆栈」的秘密

第二种收纳方式长得像一摞盘子:只能从最上面放、也只能从最上面拿,这叫栈。听着限制很大?可你每天按的撤销键、程序里每一次函数调用,靠的都是它。这一课先亲手玩坏一个文档再一键撤回来,最后围观一场「爆栈」事故——全球最大的程序员问答网站 Stack Overflow,名字就是从这场事故来的。

先玩 · 撤销键的真身

左边是个迷你文档,用四个按钮随便折腾它。留意右边:你的每一步操作都被压成一张牌,叠在「操作栈」上——后做的压在上面。折腾够了,连按几下「Cmd+Z 撤销」,看看它撤的顺序。

📄 迷你文档

随便操作,别心疼

🥞 操作栈

每步操作压一张牌,最上面 = 最近一步

(还没有操作)
试试:打两行字 → 标红 → 再撤销三次,猜猜恢复的顺序
发现了吗?撤销永远先撤最近那步。这不是产品经理的选择,是栈的天性:后进先出(LIFO,Last In First Out)。只从顶端拿,最先拿到的自然是最后放的。撤销要是不按这个顺序来——先撤掉十步前的操作——文档立刻乱成一锅粥。凡是「按原路退回去」的事,天生就该用栈收纳
程序怎么记得「回到哪」?

你让 AI「做晚饭」,它做到一半要切菜,切菜切到一半刀钝了要磨刀……每次「暂停手头的事去干别的」,程序都会把当前进度压进一个栈里。看下面的动画(滚到这里会自动播一遍),留意每个任务完成后,程序是怎么自动找回上一个任务的。

准备就绪点「播放」或滚动到这里,看一次完整的调用与返回
这个栈叫函数调用栈,每张牌叫一个「栈帧」,里面记着「这个任务干到哪了、干完回到哪」。程序不需要什么全局调度员——弹出栈顶,自然就回到了上一层暂停的位置。你学过的 Agent 也一样:主任务干到一半发现要先查资料,就把主任务压栈、先干子任务,子任务完成弹出,接着干主任务。
爆栈现场 · Stack Overflow 是怎么发生的

栈的容量是有限的。下面这个函数自己调用自己(这叫递归),左边是代码,右边是调用栈。先不勾终止条件跑一次,看看会发生什么;再勾上跑一次对比。

function 倒数(n) { if (n === 0) return; // 终止条件(保险丝) 打印(n); 倒数(n - 1); // 自己调用自己 } 倒数(5);
💥 Stack Overflow栈溢出,程序崩溃
先直接运行,看看没有保险丝的递归什么下场
这和 AI 有什么关系?关系大了。Agent 干活也是「主任务压栈、先干子任务」,那万一子任务又派生子任务、一层层没完没了呢?和没写终止条件的递归一模一样——所以所有正经的 Agent 框架都要设最大步数 / 最大深度,超过就强制停下来。那根保险丝,就是给「无限递归」上的保险。下次你看到 AI 写的递归代码,验收清单第一条:终止条件在哪?

✅ 这一课想和你分享的