Pcall 及 Coroutine

lua-users home
指南

pcall 和 coroutine 不見得一律適用。針對 Lua 5.1 的 [coxpcall] 使用 coroutine 重新建置 pcall/xpcall,以便在 pcall 中產生執行緒。另還有 ResumableVmPatch 等修補程式。Lua 5.2 (LuaFiveTwo) 實作類似的作法,像 ResumableVmPatch [1]

底下使用 coroutine 建置了 pcall/error 等函數。缺點是有每個 pcall 呼叫 coroutine 建構的額外負載。coxpcall 相當類似,但並沒有使用 coroutine.yield 重新建構 error

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"))

--DavidManura


RecentChanges · 偏好設定
編輯 · 紀錄
上次編輯:2010 年 7 月 4 日 上午 12:27 GMT (異動)