写错了不用慌。CNplus 的报错是三层的,专治「看不懂」。
写错代码时,CNplus 会这样报:
错误[CN0302]: 变量 小明 还没有声明过
--> 我的程序.cnp:1:11
|
1 | 设 名字 = 小明
| ^^^^
= 也就是说: CNplus 不认识 小明,因为你还没告诉它这个名字代表什么
= 这样改: 两种可能:一是想把「小明」当一段文字,给它加上双引号(设 名字 = "小明");二是想用变量,但还没建立它(先写 设 小明 = …)
三层结构:
| 部分 | 给谁看 | 含义 |
|---|---|---|
错误[CN0302]: … |
有基础的人 | 术语 + 稳定编号 |
--> 文件:1:11 和 ^^^^ |
所有人 | 第 1 行第 11 个字,问题就在这几个字上 |
| 也就是说 | 零基础的人 | 同一件事的大白话版 |
| 这样改 | 所有人 | 具体怎么办,经常能直接照抄 |
编号分三段,见诊断码表:
| 段 | 含义 |
|---|---|
CN01xx |
词法错误(不认识的字) |
CN02xx |
语法错误(结构不对) |
CN03xx |
语义 / 运行时错误 |
CN9001 |
你导入的 Python 库报的错(不是 CNplus 的错) |
| 码 | 症状 | 怎么改 |
|---|---|---|
CN0301 |
如果 0 之类 |
条件必须是布尔,写成 如果 x != 0 |
CN0302 |
用了没声明的名字 | 先 设 一下,或检查是不是打错字 |
CN0303 |
"字" + 1 之类 |
类型不匹配,用 文本() 转换 |
CN0304 |
除以零 | 检查除数是不是可能为 0 |
CN0307 |
设 x 写了两次 |
名字已存在,改用 x = … 赋值 |
CN0308 |
列表下标越界 / 字典缺标签 | 编号从 0 开始;先 有标签() 确认 |
CN0309 |
遍历了数字 | 换成列表/字典/字符串/范围 |
CN0310 |
程序还想要输入但输入没了 | 检查是不是按了 Ctrl+D,或喂的数据不够 |
有的错不运行程序就能查出来(cnp 检查 或编辑器里的红波浪线),这叫「静态检查」:
如果 0 # 静态就报 CN0301(字面量,一眼能确定)
打印("不会执行")
有的错要到运行时才知道(比如变量的值是多少):
设 x = 0
如果 x # 静态不报(x 的值静态不可知),运行时报 CN0301
打印("不会执行")
原则是宁可漏报也不误报——编辑器里报假警比漏报更烦人。
名字打错了,CNplus 会猜你是不是想写别的。但只在「真的很像」时才猜,认两种铁证:
年龄x 会提示「是不是想写「年龄」?(多打了后面的字符)」helo 会提示「是不是想写「hello」?」中文之间不做模糊猜测——小明、小写、小数 编辑距离都是 1,数学上分不清「打错字」和「无关词」,猜了就是误导。这种情况直接给上面那种「两种可能」的提示。
学过 Python 的人,看这里——同样的错误,Python 的报错长这样。
CNplus 报错(三层):
错误[CN0302]: 变量 小明 还没有声明过
--> 我的程序.cnp:1:11
| ^^^^
= 也就是说: CNplus 不认识 小明……
= 这样改: 两种可能……
Python 报错(只有一层术语):
NameError: name '小明' is not defined
File "我的程序.py", line 1, in <module>
| CNplus | Python | |
|---|---|---|
| 报错结构 | 术语 + 也就是说(大白话)+ 这样改(能照抄) | 只有术语,没有大白话层 |
| 定位 | --> 文件:1:11 + 波浪线 ^^^^ |
traceback 堆栈 |
| 未声明变量 | 编译期 CN0302 | 运行时 NameError |
| 诊断码 | CN0301 等,稳定编号 |
异常类名(NameError、TypeError…) |
CNplus 报错的三层结构(术语 → 大白话 → 改法)是它最大的特色之一——Python 只给你 NameError,不会告诉你「是不是忘了加引号」。学会看 CNplus 的报错,再看 Python 的报错会轻松很多,因为思路一样:先看是哪行、再看是什么错。
下一课:异常处理