LPC 异常处理:error() 与 catch() 的使用边界
LPC 没有 Java 那样完整的 try/catch 体系,驱动提供的 error() 与 catch() 构成了最基础的错误处理机制。这两个 efun 用错了位置,很容易把一次可恢复的错误升级成整个任务流程的崩溃。
error() 的行为
error() 会立即中断当前函数的执行,并沿调用栈向上回溯,直到被某一层 catch() 捕获,或者直接冒到驱动顶层。在 heart_beat()、call_out() 这类异步执行流里调用 error(),对应执行流会被直接终止,且不一定有地方能接住它。
catch() 的行为
catch(expr) 执行表达式 expr:如果执行过程出错,返回错误的描述字符串;如果一切正常,返回 0。也就是说,返回值本身就可以区分「正常」与「出错」两种结果。
使用建议
- 参数校验类的致命错误用
error(),让问题尽早暴露,不要拖到下游才以奇怪的形式显现。 - 面对外部输入(文件读取、调用其他对象、解析玩家指令)时,用
catch()包一层,保证单个异常不会拖垮主流程。 - 不要用
catch()掩盖真实 bug。捕获之后至少记一条日志,方便回溯。
// 致命错误:尽早暴露
object load_player(string id) {
if (!stringp(id) || id == "")
error("id must be a non-empty string");
// ...
}
// 外部输入:catch 兜底并记日志
mixed call_external(object ob, string fn, mixed arg) {
mixed ret;
string err = catch(ret = call_other(ob, fn, arg));
if (err) {
log_file("error", sprintf("[%s] call %s->%s failed: %s\n",
ctime(time()), base_name(ob), fn, err));
return 0;
}
return ret;
}
一句话区分:error() 表达「这里不应该发生」,catch() 表达「这里可能发生」。边界划清楚,排查问题时能少走很多弯路。