简而言之,虽然代码似乎可以正常工作,但我很好奇是否存在比目前为止更少的骇人听闻的方法。
假设您通过lua_newthread创建了一个协程,然后通过cclocure将其从lua_yield中挂起。您的程序花了非Lua代码一圈,现在是时候通过lua_resume恢复协程了,但是-假设提供Lua代码的参数极其非法,我们应该给它指明一个错误。
您可能知道,除非当前正在运行,否则无法在状态上调用lua_error(或luaL_error)。因此状态必须恢复,但立即会被错误击中。
在5.3中,您将使用lua_yieldk,提供一个延续函数,并在其中调用lua_error或luaL_error。等等。
但是,可惜-LuaJIT没有实现lua_yieldk,所以我们还有什么选择?
一次性挂钩
假设错误消息存储在char error_text[256]
中。然后,我们可以在恢复之前立即绑定每个指令的钩子,
lua_sethook(L, throw_error, LUA_MASKCOUNT, 1);
int result = lua_resume(L, NULL, ret_count);
然后解开钩子并在其中抛出错误
void throw_error(lua_State *L, lua_Debug *ar) {
lua_sethook(L, throw_error, 0, 0);
if (error_text == nullptr) return; // trust no one, especially yourself
luaL_error(L, "%s", error_text);
}
如果需要清理字符串,您当然更喜欢在调用error_text
之前将luaL_where(L, 1)
连接到_error
,就像lua_error
和luaL_error
一样跳远,因此将是您的函数要做的最后一件事。
Lua侧包装器
假设您决定对此进行某种程度的类似于node.js的操作,并使用一对error, result
对C代码进行恢复,以便可以使用像这样的包装器功能
function some(arg)
local e, r = some_native(arg)
if (e) then
error(e)
else
return r
end
end
或者完全重构您的API,以便也可以使用相同的模式来处理错误,但这又是另一回事了。
选项1似乎不那么笨拙。
选项2似乎不太可能引起任何麻烦。
我不禁感到自己有一种更好的方法被我忽略了(毕竟lua_yieldk
是相对较新的补充)。