只读表 |
|
我们可以像这样定义只读(常量)表
Directions = readonlytable { LEFT = 1, RIGHT = 2, UP = 3, DOWN = 4, otherstuff = {} }
如果我们像下面这样定义 readonlytable
辅助函数
function readonlytable(table) return setmetatable({}, { __index = table, __newindex = function(table, key, value) error("Attempt to modify read-only table") end, __metatable = false }); end
注意,readonlytable
不会返回最初传递给它的表,而是返回一个代理表。代理表被赋予一个元表,其中包含元方法 __index
和 __newindex
,以确保代理表的值永远不会改变。设置 __metatable
元方法可以防止对元表本身进行篡改——客户端无法通过 getmetatable
和 setmetatable
函数获取或更改元表。
现在,如果我们尝试修改 Directions
的任何成员,我们将得到一个错误。
> Directions.LEFT = 33
Attempt to modify read-only table
虽然无法更改只读表的成员,但仍然可以修改只读表成员的成员(除非它们也被明确地设置为只读表)。
> Directions.otherstuff = nil -- will fail Attempt to modify read-only table > Directions.otherstuff.foo = 1 -- allowed
此外,rawset()
和 table.insert
仍然可以用来直接修改只读表。
rawset(Directions, "LEFT", 5) print(Directions.LEFT) -- prints 5 table.insert(Directions, 6) print(Directions[1]) -- prints 6
如果你真的需要避免这种情况,你可以在 C 中实现只读表。
此外,这种创建只读表的方法会干扰 pairs
、ipairs
、next
、#
运算符和其他形式的表迭代。例如,
-- prints nothing! for k,v in pairs(Directions) do print(k,v) end print(next(Directions)) -- prints nil! print(#Directions) -- prints "0"!
另请参阅 广义的 Pairs 和 Ipairs,了解处理这种情况的方法。
原作者:KevinBaca