Lua中的只读迭代表?

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

function readonly(table)
    local meta = { } -- 代理元表
    local proxy = { } -- 此表永远为空

    meta.__index = table -- 引用表进行查找
    meta.__newindex = function(t, key, value)
        error("您无法对此表进行任何更改!")
    end

    setmetatable(proxy, meta)
    return proxy -- 用户将使用代理
end

它的工作非常好。

t = { }
t["Apple"] = "红"
t[true] = "正确!"
t[51] = 29

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

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

打印

红
正确!
29
input:7: 您无法对此表进行任何更改!

问题

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

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

我该如何使此只读表可迭代?

我使用的是Lua 5.1,并可以访问这些元方法:

Lua 5.1手册

点赞
用户1847592
用户1847592

你可以修改标准的 Lua 函数 pairs,使其能够正确地与只读表一起使用。

local function readonly_newindex(t, key, value)
   error("您无法对此表进行任何更改!")
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
2017-12-24 00:37:38
用户5957533
用户5957533

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

function readonly(table)
    local meta = { } -- 代理的元表
    local proxy = { } -- 这个表始终为空

    meta.__index = table -- 引用原始表格进行查找操作
    meta.__newindex = function(t, key, value)
        error("你不能修改这个表格!")
    end

    local function iter()
        return next, table
    end

    setmetatable(proxy, meta)
    return proxy, iter -- 用户将使用代理表格
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
2017-12-24 00:58:46