在lua中只读可迭代表?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在lua中只读可迭代表?相关的知识,希望对你有一定的参考价值。

我想在我的Lua程序中有一个只读表。如果删除了密钥或密钥与新值相关联,则必须抛出错误。

function readonly(table)
    local meta = { } -- metatable for proxy
    local proxy = { } -- this table is always empty

    meta.__index = table -- refer to table for lookups
    meta.__newindex = function(t, key, value)
        error("You cannot make any changes to this table!")
    end

    setmetatable(proxy, meta)
    return proxy -- user will use proxy instead
end

它很棒。

t = { }
t["Apple"] = "Red"
t[true] = "True!"
t[51] = 29

for k,v in pairs(t) do
    print(v)
end

t = readonly(t)
t[51] = 30

打印

Red
True!
29
input:7: You cannot make any changes to this table!

问题

for k, v in pairs(t) do
   print(v)
end

现在在任何情况下都不会打印。那是因为proxy表永远不会有任何内容。 pairs显然从未调用index,因此无法从实际表格中检索任何内容。

我该怎么做才能使这个只读表可迭代?

我在Lua 5.1上并且可以访问这些元方法:

Lua 5.1 Manual

答案

您可以修改标准Lua函数pairs以使您的只读表正常工作。

local function readonly_newindex(t, key, value)
   error("You cannot make any changes to this table!")
end

function readonly(tbl)
   return
      setmetatable({}, {
         __index = tbl,
         __newindex = readonly_newindex
      })
end

local original_pairs = pairs

function pairs(tbl)
   if next(tbl) == nil then
      local mt = getmetatable(tbl)
      if mt and mt.__newindex == readonly_newindex then
         tbl = mt.__index
      end
   end
   return original_pairs(tbl)
end

用法:

t = { }
t["Apple"] = "Red"
t[true] = "True!"
t[51] = 29

for k,v in pairs(t) do
   print(k, v)
end

t = readonly(t)

for k,v in pairs(t) do
   print(k, v)
end

t[51] = 30
另一答案

一种解决方案是为表创建一个完全自定义的迭代器。

function readonly(table)
    local meta = { } -- metatable for proxy
    local proxy = { } -- this table is always empty

    meta.__index = table -- refer to table for lookups
    meta.__newindex = function(t, key, value)
        error("You cannot make any changes to this table!")
    end

    local function iter()
        return next, table
    end

    setmetatable(proxy, meta)
    return proxy, iter -- user will use proxy instead
end

用法:

t = { }
t["Apple"] = "Red"
t[true] = "True!"
t[51] = 29

for k,v in pairs(t) do
    print(v)
end

t, tIter = readonly(t)
t[51] = 30

for k, v in tIter do
   print(v)
end

以上是关于在lua中只读可迭代表?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Lua 中的二维表上创建迭代器?

lua,迭代和调用n = 3层表的所有同名函数

Lua:降序表遍历第2轮:迭代器对象

lua学习之迭代器与泛型for第一篇

lua:遍历表中的所有对

迭代lua表不起作用