普贤教程 › 参考手册
错误码速查
PuXian 的报错格式统一:先是类别,再是错误码与位置,最后是人话说明。看懂这一行,八成的调试就完成了。
报错长什么样
text
运行时错误: 错误 [R1002] 1:11: 无法相加: string + int
| 位置 | 含义 |
|---|---|
| 运行时错误 / 语法错误 | 发生在运行期还是编译期 |
R1002 | 错误码 |
1:11 | 行号:列号(从 1 开始) |
无法相加: string + int | 具体原因 |
语法错误(E 系列)
| 码 | 含义 | 常见触发 |
|---|---|---|
| E2001 | 期望的记号不对 | 漏冒号、缩进错、把保留字当变量名、把赋值写成表达式 |
text
2:9: 语法错误 E2001: 期望变量名,实际得到 from 25:18: 语法错误 E2001: 期望 ')',实际得到 if 5:44: 语法错误 E2001: 期望 '}',实际得到 =
三种典型:用了保留字 from;写了三元表达式(a if c else b);在 fn 里把赋值当表达式。
运行错误(R 系列)
| 码 | 含义 | 典型触发 | 处理 |
|---|---|---|---|
| R1001 | 未定义变量 | 拼错名字;import 没生效;跨目录 import | 检查拼写与 import 路径 |
| R1002 | 类型不匹配 | "x" + 1、int("abc")、join 参数写反 | 转成同类型再运算 |
| R1004 | unwrap 失败 | 对 Err 调 unwrap() | 先判 is_err() |
| R1007 | 类型没有该字段/方法 | xs.insert()、str.status | 查可用方法清单 |
| R1008 | 字典没有该键 | d["missing"] | 先 d.has(k) |
内建函数内部失败
| 前缀 | 含义 |
|---|---|
i_call_builtin | 内建函数执行失败,如 json_parse 遇到坏 JSON、写文件失败 |
i_builtin_ffi_call | 参数类型不匹配,如把 int 传给要字符串的 tz |
it_dirname | 取路径目录时文件不存在(编译器内部) |
text
运行时错误 [i_call_builtin 行372]: io: 写入文件失败 ../build/index.html 运行时错误 [i_builtin_ffi_call 行1284]: R1002: time_format 的 tz 需要字符串,实际是 int 运行时错误 [it_dirname 行161]: io: 读取文件失败 bench.px
按报错找原因:速查
| 报错 | 八成是什么 |
|---|---|
| 未定义变量: 'xxx' | 函数名拼错;或 import 没写;或用了 keys(d) 这类不存在的内建 |
| 无法相加: string + int | 拼接前忘了 str() |
| 无法将 'abc' 转为 int | 外部输入没校验就 int() |
| 字典没有键 | 直接读可能不存在的键 |
| 类型 list 没有方法 'insert' | 记成了 Python 的 API |
| 期望变量名,实际得到 XXX | 用了保留字(from / in / type 之外的) |
| 写入文件失败 | 父目录不存在或无权限 |
| 段错误(Segmentation fault) | 函数名与内建同名导致递归(如 def env()) |
调试手段
- 打点:
print("到这里 " + str(x))。解释轨里最直接。 - 缩小范围:把出错行前后各删一半,看错误消失在哪一步。
- 静态检查:
px lint x.px能在运行前抓到语法与部分语义问题。 - 看行列号:报错给的是精确位置,别只看行号忽略列号——同一行里
+左边还是右边出错,结果完全不同。 - 日志走 stderr:在 Ma 的 px_routes 里,
print会污染响应体,调试输出必须写/dev/stderr。
错误处理的正确姿势
| 场景 | 做法 |
|---|---|
| 可预期的失败(文件不存在、参数不合法) | 返回 Ok / Err,调用方处理 |
| 不可能发生的内部错误 | 让它崩,日志里留下行列号 |
| 外部数据 | 先校验,再调用会终止进程的函数(int、json_parse) |
| 接口入口 | 包一层统一返回 400/500,别让子进程崩掉整个请求 |
px
# 入口处兜底:任何异常输入都变成 400,而不是 500 def guard(raw, fn): var p = json_parse_opt(raw) if p.is_err(): return {"status": 400, "body": {"ok": false, "error": "请求体不是合法 JSON"}} return fn(p.ok())