Lua Carp

lua-users home
wiki

Lua 的 [error] 函數接受一個選擇性的 level 參數,表示在產生錯誤訊息時,應歸咎於呼叫堆疊中的誰。現在,這並不總是可擴充性的,因為追蹤層級容易出錯(特別是在重構之後),而且使用 error 的函數可能在許多不同的層級中呼叫。

解決方案 A

以下的解決方案基於 [Perl's Carp] 模組,但已改寫成 Lua。這提供了一個 croak 函數,作為 error 的替代。croak 呼叫 error,但在這麼做之前,它會透過查詢呼叫堆疊尋找,直到目前環境改變為止,藉此決定要使用哪個層級。

首先,以下是主模組

-- Carp.lua
-- This package is based on Perl Carp
-- (http://search.cpan.org/~nwclark/perl-5.8.8/lib/Carp.pm)
-- David Manura, 2006-09, 2007-07

local M = {}

function M.croak(message)
  local current_env = getfenv(2)
  local level = 2
  while true do
    local is_success, result = pcall(function()
      return getfenv(level + 2)
    end)
    if is_success then
      local env = result
      --print("DEBUG:level", level, env._NAME)
      if env ~= current_env then
        --print("DEBUG:found", level, env._NAME)
        error(message, level)
      end
    elseif string.find(result, "(invalid level)") then
      break
    end
    level = level + 1
  end
end

return M

現在假設您撰寫一個模組

-- Calculator.lua

-- Create environment for module (needed for Carp)
local env = setmetatable({}, {__index = _G})
setfenv(1, env)

local M = {} 
local Carp = require "Carp"

function M.calculate3()
  Carp.croak("calculation failed")
  return 1
end

function M.calculate2()
  local result = M.calculate3()
  return result + 1
end

function M.calculate()
  return M.calculate2()
end

return M

然後您撰寫一個使用該模組的程式

-- example.lua
-- This uses the calculator module.

local Calc = require "Calculator"

local function main()
  local result = Calc.calculate()
  print(result)
end

main()

以下是輸出

lua: example.lua:7: calculation failed
stack traceback:
        [C]: in function 'error'
        ./Carp.lua:20: in function 'croak'
        ./Calculator.lua:10: in function 'calculate3'
        ./Calculator.lua:15: in function <./Calculator.lua:14>
        (tail call): ?
        example.lua:7: in function 'main'
        example.lua:11: in main chunk
        [C]: ?

注意:這可能無法正確運作於尾呼叫。Lua 沒有為尾呼叫報告環境,所以它們會被略過。

其他解決方案

RiciLake 提出的第二個解決方案是撰寫一個自訂追蹤函數,這點子的概念是追蹤函數會在每個層級檢查 env 表格,直到與目前層級不同,它才會開始產生追蹤碼。

RiciLake 提出的第三個解決方案很簡單,只要在每個區塊中檢查堆疊索引 1 的物件,這點子的概念是如果階層方法呼叫,您總會擁有相同的自我,但有時會過度。這會希望以某種方式標記堆疊,但顯然不知道如何這麼做。

待辦事項 - 對這些方法的優劣,任何人有意見嗎?

注意:此程式碼相容於 Lua 5.1(而非 5.0)。

--DavidManura


RecentChanges · 喜好設定
編輯 · 歷程
最近編輯時間是 2007 年 8 月 9 日,星期四,上午 3:16(格林威治標準時間),(差異)