跑测试时终端刷出一行 AssertionError,或者打开某个软件弹出「Assertion failed」,点确定程序就退了。这不是系统崩溃,是代码自己发现不对劲,主动停下来的。
断言是干什么的
assert 是编程语言里的检查语句,后面跟一个条件,条件为真就继续,为假就报错终止。C 语言里写 assert(p != NULL),指针为空时直接 abort,并打印文件名和行号。Python 的 assert 失败抛出 AssertionError,Node.js 的 assert 模块会抛出带差异信息的 AssertionError。它的用途是抓「本不该发生」的情况,不是处理用户输入错误。Java 的 assert 默认关闭,运行时加 -ea 参数才生效。
报错信息怎么读
C 里的典型输出会带上断言表达式、文件名和行号。先看表达式,再看文件和行号,去源码对应位置找上下文。Python 会给出 Traceback,最下面一行就是出错的位置,往上翻能看到一层层调用链和传进来的参数。浏览器控制台或测试框架会给期望值和实际值,两个数一对,问题基本就露出来了。
常见触发原因
- 指针或对象为空,代码假设它一定有值。
- 数组下标越界,或者容器长度和实际不符。
- 函数参数不满足前置条件,比如要求正数传了 0。
- 多线程下数据被改,条件检查的瞬间就失效了。
怎么处理才算对
别急着把 assert 删掉或者注释掉,那等于把烟雾报警器拆了。先复现,记录输入和调用栈,用调试器断在断言处看变量值。确认是代码逻辑问题就修逻辑,确认是外部数据问题就在入口做校验。发布版本一般会定义 NDEBUG 关掉 assert,所以它不能代替错误处理,用户输入该判断还得判断。断言和异常不是一回事,断言查的是程序内部逻辑,异常处理的是可预期的运行时错误。日志里记下断言所在的函数和参数,方便复现,顺手补一个回归测试,防止下次再犯。
看到这类报错,正确的反应是「哪个假设不成立」,找到那个前提,比改报错文字有用。