【问题标题】:Read only iterable table in lua?lua中的只读可迭代表?
【发布时间】:2018-06-06 00:27:53
【问题描述】:

我想在我的 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 lua-table


    【解决方案1】:

    您可以修改标准 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
    

    【讨论】:

      【解决方案2】:

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

      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 5.2+ 有 __pairs/__ipairs 元方法,因此没有必要显式返回/使用自定义迭代器。 pair()/ipairs() 可以隐式使用该自定义迭代器。
      • @Vlad True,这是我最初的想法,但 OP 使用的是 5.1,因此该解决方案不可用。
      猜你喜欢
      • 2012-11-09
      • 2012-09-15
      • 1970-01-01
      • 1970-01-01
      • 2017-12-08
      • 2017-10-17
      • 2012-05-27
      • 2015-05-31
      • 1970-01-01
      相关资源
      最近更新 更多