为什么这段代码意味着所有表共享一个单一的元表

时间:2019-07-08 04:54:06

标签: lua lua-table

我有一个要求所有只读表可以共享一个元表,代码短语可以满足此要求,但是我不明白该代码短语如何实现该目标

local index = {}
local mt = {
  __index = function ( t, k )
    return t[index][k]
  end,

  __newindex = function ( t, k, v )
    -- body
    error("update the value is prohibited",2)
  end
}



function readonly(t)
  local proxy = {}
  proxy[index] = t
  setmetatable(proxy,mt)
  return proxy
end

1 个答案:

答案 0 :(得分:1)

您提供的代码似乎是尝试使用代理表模式。它可以工作,但不是“只读表”的有效实现。那是因为您的代理表中包含对本应涵盖的表的引用。它存储在键等于index的字段中。这意味着您可以轻松地编辑应为只读的值,例如:

local A = readonly {foo = 7}
print(A.foo) -- prints: 7
local _,ro = next(A)
ro.foo = 17
print(A.foo) -- prints: 17

“代理表”应如何工作?简而言之,整个想法是使用一个空表作为用户和只读表之间的代理。我们将具有__index__newindex元方法的元表分配给代理表。

    每当用户尝试访问“持有”值__index的字段时,都会调用
  • nil
  • 每当用户尝试在表中创建新字段时,都会调用
  • __newindex

由于我们的代理表始终为空,因此每次分配都会触发__newindex

local B = readonly {bar = 8}
B.foo = 7 -- non-existent in both proxy and readonly table -> calls __newindex
B.bar = 3 -- exists in readonly table but does not exist in proxy -> calls __newindex

出于相同的原因,每次访问字段__index都会出现:

local B = readonly {bar = 8}
print(B.foo) -- does not exist in proxy, __index is called -> prints "nil"
print(B.bar) -- does not exist in proxy, __index is called -> prints "8"

有关更有效的示例,请参见下文。它仍然存在问题(例如,可以更改表模式以使键变弱;请参见注释),但至少它涵盖了只读表。

local index = {}

local mt = {
  __index = function (t, k)
    return index[t][k]
  end,
  __newindex = function ()
    -- body
    error("update the value is prohibited",2)
  end,
}

function readonly (t)
  local proxy = {}
  index[proxy] = t
  setmetatable(proxy, mt)
  return proxy
end

如有疑问,您可以参考:

相关问题