CLASS 13 · 2026-03-30 · 11-13 递归与解析

调试

调试的第一原则是尽量不去调试:用类型系统、检查和不变性让 bug 在写下的那一刻就无处藏身。当 bug 仍然出现时,用科学方法系统地复现、假设、实验和修复,而不是靠运气。

常见 bug 类型

在动手之前,先认识几类最常出没的 bug,有助于你快速识别它们:

第一道防线:让 bug 不可能出现

最强大的调试,是在 bug 写出来之前就消灭它。6.102 提供三种机制:

// 用不变性消除别名 bug
const original: readonly number[] = [1, 2, 3];
// original.push(4); // 编译错误:无法修改只读数组

第二道防线:让 bug 容易定位

当无法完全避免 bug 时,要让它们尽早暴露:

function sqrt(x: number): number {
  console.assert(x >= 0, "sqrt 的参数必须非负");
  return Math.sqrt(x);
}

复现 bug

定位 bug 的第一步是找到一个小的、可重复的测试用例,能稳定触发失败。如果 bug 时有时无,先不要急着改代码,而是缩小输入、固定随机种子,直到失败变成必然。

用科学方法定位 bug

调试本质上是一个循环的科学实验:

  1. 研究数据:观察输入、输出、错误信息、日志。
  2. 提出假设:对 bug 原因给出一个可验证的解释。
  3. 设计实验:用探针验证或推翻假设。
  4. 重复:直到定位根因。

探针工具

delta 调试

Delta 调试的思路是对比成功运行与失败运行的差异,逐步缩小导致失败的最小输入或最小代码变更。这是一种系统化的二分搜索。

修复 bug

找到根因后,修复应该是谨慎而完整的:

其他调试技巧

关键要点

  • 预防静态检查 + 动态检查 + 不变性,让 bug 不可能出现。
  • 暴露快速失败、断言、增量开发、模块化,让 bug 尽早暴露。
  • 复现找到最小可重复的测试用例。
  • 科学研究数据 → 假设 → 实验 → 重复,系统定位根因。
  • 修复撤探针、写回归测试、提交并反思。