为什么这段代码意味着所有表共享一个元表
why this code means that all tables share a single metatable
我得到一个要求,所有只读表都可以共享一个元表,代码短语满足了这个要求,但我不明白这个代码短语是如何实现这个目标的
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
您提供的代码似乎是尝试使用代理 Table 模式。它可以工作,但它不是 "read-only tables" 的有效实现。那是因为您的代理 table 持有对它应该覆盖的 table 的引用。它存储在一个键等于 index
的字段中。这意味着可以轻松编辑应为 read-only 的值,例如:
local A = readonly {foo = 7}
print(A.foo) -- prints: 7
local _,ro = next(A)
ro.foo = 17
print(A.foo) -- prints: 17
"Proxy Table" 应该如何工作?简而言之,整个想法是使用空 table 作为用户和 read-only table 之间的代理。我们将具有 __index
和 __newindex
元方法的元 table 分配给代理 table.
__index
每当有人试图访问 "holds" 值 nil
. 的字段时调用
__newindex
每当有人尝试在 table. 中创建新字段时调用
由于我们的代理table总是空的,每次赋值都会触发__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"
至于更有效的示例,请参见下文。它仍然存在问题(例如 table 模式可以更改为弱键;请参阅评论),但至少它涵盖了 read-only table.
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
如有疑问可参考:
我得到一个要求,所有只读表都可以共享一个元表,代码短语满足了这个要求,但我不明白这个代码短语是如何实现这个目标的
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
您提供的代码似乎是尝试使用代理 Table 模式。它可以工作,但它不是 "read-only tables" 的有效实现。那是因为您的代理 table 持有对它应该覆盖的 table 的引用。它存储在一个键等于 index
的字段中。这意味着可以轻松编辑应为 read-only 的值,例如:
local A = readonly {foo = 7}
print(A.foo) -- prints: 7
local _,ro = next(A)
ro.foo = 17
print(A.foo) -- prints: 17
"Proxy Table" 应该如何工作?简而言之,整个想法是使用空 table 作为用户和 read-only table 之间的代理。我们将具有 __index
和 __newindex
元方法的元 table 分配给代理 table.
__index
每当有人试图访问 "holds" 值nil
. 的字段时调用
__newindex
每当有人尝试在 table. 中创建新字段时调用
由于我们的代理table总是空的,每次赋值都会触发__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"
至于更有效的示例,请参见下文。它仍然存在问题(例如 table 模式可以更改为弱键;请参阅评论),但至少它涵盖了 read-only table.
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
如有疑问可参考: