How to set table as read-only property in Lua

Time:2021-10-20

Some read-only tables in the project are easy to be rewritten by mistake, so it is decided to attach these tables in a non online environmentRead only attribute, it is convenient to throw Lua errors in case of misrewriting. The final version code is as follows:

  1. –[[—————————————————————————— 
  2. -**   Set table read-only   Lua will be thrown when rewriting occurs   error
  3. —   usage   local   cfg_ proxy  =  read_ only(cfg)   retur   cfg_ proxy
  4. —   Added anti reset setting read_ Only mechanism
  5. —   Lua5.3 support   1) The table library supports calling meta methods, so table.remove   table.insert   It also throws errors,
  6. —    2) No definition__ ipairs   five point three   The ipairs iterator supports access to meta methods__ Index, pairs iterator next does not support, so meta method is required__ pairs
  7. —   In earlier versions Lua, this function does not work exactly as expected
  8. *]] 
  9. function read_only(inputTable) 
  10.  local travelled_tables = {} 
  11.  local function __read_only(tbl) 
  12.  if not travelled_tables[tbl] then 
  13.   local tbl_mt = getmetatable(tbl) 
  14.   if not tbl_mt then 
  15.   tbl_mt = {} 
  16.   setmetatable(tbl, tbl_mt) 
  17.   end 
  18.  
  19.   local proxy = tbl_mt.__read_only_proxy 
  20.   if not proxy then 
  21.   proxy = {} 
  22.   tbl_mt.__read_only_proxy = proxy 
  23.   local proxy_mt = { 
  24.    __index = tbl, 
  25.    __newindex = function (t, k, v) error(“error write to a read-only table with key = ” .. tostring(k)) end, 
  26.    __pairs = function (t) return pairs(tbl) end, 
  27. —  __ ipairs  =  function   (t)   return   ipairs(tbl)   end,   This method is not required in version 5.3
  28.    __len = function (t) return #tbl end, 
  29.    __read_only_proxy = proxy 
  30.   } 
  31.   setmetatable(proxy, proxy_mt) 
  32.   end 
  33.   travelled_tables[tbl] = proxy 
  34.   for k, v in pairs(tbl) do 
  35.   if type(v) == “table” then 
  36.    tbl[k] = __read_only(v) 
  37.   end 
  38.   end 
  39.  end 
  40.  return travelled_tables[tbl] 
  41.  end 
  42.  return __read_only(inputTable) 
  43. end 

The test code is as follows:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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=t1
 
local t3 = read_only(t1)
 
print(t3.d, t3.c.e, t3.c.c.b.t2.fdsf)
function q1() t3.d = 4555 end
function q2() t3.c.d = 90 end
function q3() t3.c.c.b.t2.fdsf =90 end
function q4() table.remove(t3.a) end
function q5() t3.b[ddss] = nil end
function q6() t3[f] = 89 end
function q7() table.insert(t3.a, 999) end
 
print(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)
end
for k,v in pairs(t3.a) do
 print("===pairs t3.a:",k,v)
end
for k,v in ipairs(t3) do
 print("===ipairs t3:",k,v)
end
for k,v in ipairs(t3.a) do
 print("===ipair t3.a",k,v)
end
print("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)

testing environment https://www.lua.org/cgi-bin/demo   lua5.3.4:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
string table: 0x20d4ba0
false input:17: error write to a read-only table with key = d
false input:17: error write to a read-only table with key = d
false input:17: error write to a read-only table with key = fdsf
false input:17: error write to a read-only table with key = 2
false input:17: error write to a read-only table with key = nil
false input:17: error write to a read-only table with key = nil
false 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 89
len t3: 0
len t3.a: 2
table: 0x20d4870 table: 0x20d4870
table: 0x20d5690 table: 0x20d5690 table: 0x20d1140

Code idea design:

1. Useproxy={}Empty table instead of target TABLE tbl__ Newindex is because__ Newindex can only be called if it does not exist in the original table, so that the existing fields can still be overwritten

?
1
2
3
4
5
__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. Avoid cross referencing of tables and add travelled_ Tables stores the mapping of tables for which proxy has been set

3. Access to the original TABLE tbl__index=tbl

4. For table check length, use__len= function () return #tbl end

5. For traversing pairs, it is found that the default iterator next of pairs in lua5.3 does not support accessing meta tables__ Index, so direct__pairs = function () return pairs(tbl) endTo generate an iterative traversal of the target table

6. For ipairs, the iterator generated by lua5.3 ipairs function supports accessing meta tables by default__ Index, so there is no need to add__ ipairs

     8.2 – Changes in the Libraries

     •The ipairs iterator now respects metamethods and its __ipairs metamethod has been deprecated.

7. Fortable.insert , table.removeWithout special treatment, lua5.3’s table lib supports meta table operation, so errors will still be thrown

      8.2 – Changes in the Libraries

      •The Table library now respects metamethods for setting and getting elements.

8. Avoid creating read repeatedly_ Only, only one proxy proxy is created for each TBL, and the properties are set in the metatable of TBL and the metatable of proxy__ read_ only_ Proxy, which can be accessed directly

summary

The above is the whole content of this article. I hope the content of this article can bring some help to your study or work. If you have any questions, you can leave a message. Thank you for your support for developepper.