Lua Carp |
|
level
參數,表示在產生錯誤訊息時,應歸咎於呼叫堆疊中的誰。現在,這並不總是可擴充性的,因為追蹤層級容易出錯(特別是在重構之後),而且使用 error
的函數可能在許多不同的層級中呼叫。
以下的解決方案基於 [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)。