項目中部分只讀表易被人誤改寫,故決定在非線上環(huán)境里對這些表附加只讀屬性,方便在出現(xiàn)誤改寫的時候拋出lua/269325.html">lua錯誤,最終版代碼如下:
--[[-------------------------------------------------------------------------------** 設置table只讀 出現(xiàn)改寫會拋出lua error-- 用法 local cfg_proxy = read_only(cfg) retur cfg_proxy-- 增加了防重置設置read_only的機制-- lua5.3支持 1)table庫支持調用元方法,所以table.remove table.insert 也會拋出錯誤,-- 2)不用定義__ipairs 5.3 ipairs迭代器支持訪問元方法__index,pairs迭代器next不支持故需要元方法__pairs-- 低版本lua此函數(shù)不能完全按照預期工作*]]function read_only(inputTable) local travelled_tables = {} local function __read_only(tbl) if not travelled_tables[tbl] then local tbl_mt = getmetatable(tbl) if not tbl_mt then tbl_mt = {} setmetatable(tbl, tbl_mt) end local proxy = tbl_mt.__read_only_proxy if not proxy then proxy = {} tbl_mt.__read_only_proxy = proxy local proxy_mt = { __index = tbl, __newindex = function (t, k, v) error("error write to a read-only table with key = " .. tostring(k)) end, __pairs = function (t) return pairs(tbl) end, -- __ipairs = function (t) return ipairs(tbl) end, 5.3版本不需要此方法 __len = function (t) return #tbl end, __read_only_proxy = proxy } setmetatable(proxy, proxy_mt) end travelled_tables[tbl] = proxy for k, v in pairs(tbl) do if type(v) == "table" then tbl[k] = __read_only(v) end end end return travelled_tables[tbl] end return __read_only(inputTable)end
測試代碼如下:
local t0 = {k = 1}local t2 = { fdsf = {456}}local t1 = { a = {456, 89}, b = {456,ddss = 9, t2 = t2}, d = 45, e = "string",}t1.c=t1local t3 = read_only(t1)print(t3.d, t3.c.e, t3.c.c.b.t2.fdsf)function q1() t3.d = 4555 endfunction q2() t3.c.d = 90 endfunction q3() t3.c.c.b.t2.fdsf =90 endfunction q4() table.remove(t3.a) endfunction q5() t3.b[ddss] = nil endfunction q6() t3[f] = 89 endfunction q7() table.insert(t3.a, 999) endprint(pcall(q1))print(pcall(q2))print(pcall(q3))print(pcall(q4))print(pcall(q5))print(pcall(q6))print(pcall(q7))print(t3.a[1])for k,v in pairs(t3) do print("===pairs t3:",k,v)endfor k,v in pairs(t3.a) do print("===pairs t3.a:",k,v)endfor k,v in ipairs(t3) do print("===ipairs t3:",k,v)endfor k,v in ipairs(t3.a) do print("===ipair t3.a",k,v)endprint("len t3:",#t3)print("len t3.a:", #t3.a)local t4 = read_only(t2)local t5 = read_only(t0)local t6 = read_only(t0)print(t3.b.t2, read_only(t2))print(t5, t6, t0)
測試環(huán)境https://www.lua.org/cgi-bin/demo lua5.3.4:
string table: 0x20d4ba0false input:17: error write to a read-only table with key = dfalse input:17: error write to a read-only table with key = dfalse input:17: error write to a read-only table with key = fdsffalse input:17: error write to a read-only table with key = 2false input:17: error write to a read-only table with key = nilfalse input:17: error write to a read-only table with key = nilfalse input:17: error write to a read-only table with key = 3===pairs t3: e string===pairs t3: b table: 0x20ccd60===pairs t3: a table: 0x20d4e70===pairs t3: d 45===pairs t3: c table: 0x20ca700===pairs t3.a: 1 456===pairs t3.a: 2 89===ipair t3.a 1 456===ipair t3.a 2 89len t3: 0len t3.a: 2table: 0x20d4870 table: 0x20d4870table: 0x20d5690 table: 0x20d5690 table: 0x20d1140
代碼思路設計:
1.使用proxy={}
空表而不是目標表tbl來設置__newindex是因為__newindex必須在原表里面不存在才會調用,這樣就依然可以對已存在的字段進行改寫
__newindex: The indexing assignment table[key] = value. Like the index event, this event happens when table is not a table or when key is not present in table. The metamethod is looked up in table.Like with indexing, the metamethod for this event can be either a function or a table. If it is a function, it is called with table, key, and value as arguments. If it is a table, Lua does an indexing assignment to this table with the same key and value. (This assignment is regular, not raw, and therefore can trigger another metamethod.)Whenever there is a __newindex metamethod, Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)
2.避免出現(xiàn)table的互相引用,加入travelled_tables存儲已經(jīng)設置過proxy的table的映射
3.對于原表tbl的訪問使用__index=tbl
4.對于表查長度使用__len= function () return #tbl end
5.對于遍歷pairs,查到lua5.3的pairs默認迭代器next不支持訪問元表__index,故直接__pairs = function () return pairs(tbl) end
,以此來生成對目標表的迭代遍歷
6.對于ipairs,查到lua5.3 ipairs函數(shù)生成的迭代器默認就支持訪問元表__index,故不需要添加__ipairs
8.2 – Changes in the Libraries
•The ipairs iterator now respects metamethods and its __ipairs metamethod has been deprecated.
7.對于table.insert
, table.remove
不用特殊處理,lua5.3的table lib支持元表操作,故依然會拋錯
8.2 – Changes in the Libraries
•The Table library now respects metamethods for setting and getting elements.
8.避免重復創(chuàng)建read_only,每個tbl只創(chuàng)建一個proxy代理,在tbl的metatable里和proxy的metatable里都設置屬性__read_only_proxy,可以直接訪問獲得
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網(wǎng)的支持。
新聞熱點
疑難解答