Pcall 和协程 |
|
下面使用协程实现了类似于 pcall/error
的函数。 缺点是每个 pcall 都会产生协程构造的开销。 coxpcall 非常类似,但它没有将 error
重新实现为 coroutine.yield
。
local function tuple(...) return {n=select('#', ...), ...} end function pcall(f, ...) local co = coroutine.create(f) local res = tuple(coroutine.resume(co, ...)) if res[1] and coroutine.status(co) == "suspended" then res[1] = false end return unpack(res, 1, res.n) end local handlers = setmetatable({}, {__mode='kv'}) function xpcall(f, err, ...) local co = coroutine.create(f) handlers[co] = err local res = tuple(coroutine.resume(co, ...)) if res[1] and coroutine.status(co) == "suspended" then res[1] = false end if not res[1] and err then res[2] = err(co, res[2]) -- note: assumes err can accept coroutine as first argument. end return unpack(res, 1, res.n) end function error(e, level_) --FIX:level not handled coroutine.yield(e) end -- test local function g(x) if x == "fail" then error "fail" elseif x == "fail2" then local y = nil + nil -- error raised by Lua end end local function f(x) print(1) g(x) print(2) return 3,4 end print(pcall(f, "ok")) print(pcall(f, "fail")) print(pcall(f, "fail2")) print(xpcall(f, debug.traceback, "fail")) print(xpcall(f, debug.traceback, "fail2"))