如何在 lua 中实现只读 table?
How can I implement a read-only table in lua?
我写了一个例子。
function readOnly(t)
local newTable = {}
local metaTable = {}
metaTable.__index = t
metaTable.__newindex = function(tbl, key, value) error("Data cannot be changed!") end
setmetatable(newTable, metaTable)
return newTable
end
local tbl = {
sex = {
male = 1,
female = 1,
},
identity = {
police = 1,
student = 2,
doctor = {
physician = 1,
oculist = 2,
}
}
}
local hold = readOnly(tbl)
print(hold.sex)
hold.sex = 2 --error
这意味着我可以访问 table "tbl" 的字段,但同时我不能更改与该字段相关的值。
现在,问题是我想让所有嵌套的 table 拥有这个只读
property.How 我可以改进 "readOnly" 方法吗?
您只需将 readOnly
函数也递归地应用于内部 table 字段。您可以在 __index
元方法中按访问方式执行此操作。您还应该缓存您创建的只读代理 tables,否则对内部 tables(例如 hold.sex
)的任何读取访问都将创建一个新代理 table.
-- remember mappings from original table to proxy table
local proxies = setmetatable( {}, { __mode = "k" } )
function readOnly( t )
if type( t ) == "table" then
-- check whether we already have a readonly proxy for this table
local p = proxies[ t ]
if not p then
-- create new proxy table for t
p = setmetatable( {}, {
__index = function( _, k )
-- apply `readonly` recursively to field `t[k]`
return readOnly( t[ k ] )
end,
__newindex = function()
error( "table is readonly", 2 )
end,
} )
proxies[ t ] = p
end
return p
else
-- non-tables are returned as is
return t
end
end
我写了一个例子。
function readOnly(t)
local newTable = {}
local metaTable = {}
metaTable.__index = t
metaTable.__newindex = function(tbl, key, value) error("Data cannot be changed!") end
setmetatable(newTable, metaTable)
return newTable
end
local tbl = {
sex = {
male = 1,
female = 1,
},
identity = {
police = 1,
student = 2,
doctor = {
physician = 1,
oculist = 2,
}
}
}
local hold = readOnly(tbl)
print(hold.sex)
hold.sex = 2 --error
这意味着我可以访问 table "tbl" 的字段,但同时我不能更改与该字段相关的值。
现在,问题是我想让所有嵌套的 table 拥有这个只读 property.How 我可以改进 "readOnly" 方法吗?
您只需将 readOnly
函数也递归地应用于内部 table 字段。您可以在 __index
元方法中按访问方式执行此操作。您还应该缓存您创建的只读代理 tables,否则对内部 tables(例如 hold.sex
)的任何读取访问都将创建一个新代理 table.
-- remember mappings from original table to proxy table
local proxies = setmetatable( {}, { __mode = "k" } )
function readOnly( t )
if type( t ) == "table" then
-- check whether we already have a readonly proxy for this table
local p = proxies[ t ]
if not p then
-- create new proxy table for t
p = setmetatable( {}, {
__index = function( _, k )
-- apply `readonly` recursively to field `t[k]`
return readOnly( t[ k ] )
end,
__newindex = function()
error( "table is readonly", 2 )
end,
} )
proxies[ t ] = p
end
return p
else
-- non-tables are returned as is
return t
end
end