メタテーブルとシャドウ テーブルを使用して、キーが追加および変更された元の順序を記録する履歴追跡テーブルを作成できます。
これは簡単にテストされた例で、名前を付けて保存しtrack.lua
ます:
-- tracking table that keeps a history of keys in the
-- order they were added to the table.
-- safe markers to store to track the use of nil or NaN
-- as either keys or values. Neither can be a key, and
-- nil cannot be a value in a sequence. Note that the history
-- iterator will assume that the record of keys is a valid
-- sequence.
local nilmarker, nanmarker = newproxy(), newproxy()
-- Make a value that can server as either key or value in a
-- table, even if it is nil or NaN, neither of which can be
-- a table key or a value in a valid sequence.
local function safemark(v)
if v == nil then return nilmarker end
if v ~= v then return nanmarker end
return v
end
-- Set a key and track it's history, potentially including
-- deletions since we use safe markers in the tracking tables.
local function t_newindex(t,k,v)
local mt = getmetatable(t)
if mt.__index ~= mt.shadow or not mt.shadow[k] then
mt.k[#mt.k+1] = safemark(k)
mt.v[#mt.v+1] = safemark(v)
end
mt.shadow[k] = v
return mt and mt.shadow and mt.shadow[k]
end
-- Look up a key in the shadow table
local function t_index(t,k)
return getmetatable(t).shadow[k]
end
-- simple module table
local tracked = {}
-- create a new table with tracked keys and values. If called
-- with no argument or false, only key creation and initial values
-- are tracked. If called with true, then every value change will
-- be tracked.
function tracked.new(fullhistory)
local mt = {
__newindex = t_newindex,
shadow = {},
k = {},
v = {},
}
mt.__index = fullhistory and t_index or mt.shadow
return setmetatable({},mt)
end
-- return a human-readable string describing a value,
-- paying attention to our private marks for nil and NaN
local function tracked.safe(v)
if v == nilmarker then return "~~nil~~" end
if v == nanmarker then return "~~nan~~" end
return tostring(v)
end
-- return an iterator in history order of the keys and values
-- as they were created and updated. The history records nil
-- and NaN via private markers. To test for those markers, use
-- tracked.safe() to convert the possibly marked values to strings.
function tracked.history(t)
local i = 0
local mt = getmetatable(t)
local k,v = mt.k, mt.v
return function()
i = i + 1
return k[i], v[i]
end
end
return tracked
モジュールパスで「track.lua」として利用できると仮定すると、次のように使用できます。
C:\Users\Ross\Documents\tmp\SOQuestions>lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org、PUC-Rio
> トラック = 「q19953449」が必要
> t = track.new(真)
>た=1
> tb = 2
>た=0
> tc = 3
> track.history(t) の k,v に対して print(k,v) end を実行
1
b 2
0
c 3
> tc = ゼロ
> track.history(t) の k,v に対して print(k,v) end を実行
1
b 2
0
c 3
c ユーザーデータ: 007FD638
>td = 0/0
> track.history(t) の k,v に対して print(k,v) end を実行
1
b 2
0
c 3
c ユーザーデータ: 007FD638
d ユーザーデータ: 007FD658
> =td
-1.#IND
> =tc
なし
> ^Z