虽然能够使用任何类型的值作为错误对象,但错误对象通常是一个描述出错的字符串。当遇到内部错误(比如尝试对一个非表类型的值进行索引操作)出现时, Lua
语言负责产生错误对象(这种情况下的错误对象永远是字符串;而在其他情况下,错误对象就是传递给函数 error
的值)。如果错误对象是一个字符串,那么 Lua
语言还会尝试把一些有关错误发生位置的信息附上:
local status, err = pcall(function () error("my error") end) print(err) --> stdin:1: my error
位置信息中给出了出错代码段的名称(上例中的 stdin
)和行号(上例中的 1
)。
函数 error
还有第 2
个可选参数 level
,用于指出函数调用层次中的那层函数报告错误,以说明谁应该为错误负责。例如,假设编写一个用来检查其自身是否被正确调用了的函数:
function foo(str) if type(str) ~= "string" then error("string expected") end -- 常规代码 end
如果调用时被传递了错误的参数:
foo({x=1})
由于是函数 foo
调用的 error
,所以 Lua
语言会认为是函数 foo
发生了错误。然而,真正的肇事者其实是函数 foo
的调用者。为了纠正这个问题,我们需要告诉 error
函数错误实际发生在函数调用层次的第 2
层中(第 1
层是 foo
函数自己):
function foo (str) if type(str) ~= "string" then error("string expected", 2) end -- 常规代码 end
通常,除了发生错误的位置以外,我们还希望在错误发生时得到更多的调试信息。至少,我们希望得到具有发生错误时完成函数调用栈的栈回溯( traceback
)。当函数 pcall
返回错误信息时,部分的调用栈已经被破坏了(从 pcall
到出错之处的部分)。因此,如果希望得到一个有意义的栈回溯,那么就必须在函数 pcall
返回前先将调用栈构造好。为了完成这个需求, Lua
语言提供了函数 xpcall
。该函数与函数 pcall
类似,但它的第 2
个参数是一个消息处理函数。当发生错误时, Lua
会在调用栈展开前调用这个消息处理函数,以便消息处理函数能够使用调试库来获取有关错误的更多信息。两个常用的消息处理函数如下所示:
debug.debug
:为用户提供了一个Lua
提示符来让用户检查错误发生的原因。debug.traceback
:使用调用栈来构造详细的错误信息,Lua
语言的独立解释器就是使用这个函数来构造错误信息的。