如何记录嵌套tableaccesses/writes?
How to log nested table accesses/writes?
作为我正在处理的项目的一部分,我希望能够在访问或写入 table 时打印出来,以及 accessed/written 在 [=38 中的内容=].查找此内容,我发现 this,它描述了如何通过使用代理 table 以及 __index
和 [=14 来跟踪何时 table 是 accessed/updated =] 元方法。但是,如果将嵌套 table 用作代理 table,则它们提供的代码无法正确显示正在发生的情况。假设我编写了以下代码,改编自上一个代码:
mt = {}
function mt.__index(self, key)
print('accessing key '..key)
return self.proxy[key]
end
function mt.__newindex(self, key, value)
print('setting key '..key..' to value '..tostring(value))
self.proxy[key] = value
end
function setproxy(t)
new_t = {proxy = t}
setmetatable(new_t, mt)
return new_t
end
t = {
a = 1,
b = 2,
c = {
a = 3,
b = 4,
},
}
t = setproxy(t)
t.a = 2 -- prints "setting key a to value 2" as expected
t.c.a = 4 -- prints "accessing key c", nothing else
这里的问题是 __index
被调用来访问密钥 c
并且它 returns 代理 table 中的一个值,但是没有相同的 metatable,因此它不会记录对 t.c
的写入。我希望第二个作业打印类似 setting key c.a to value 4
的内容,但我不确定从哪里开始实际实现这样的事情。
经过深思熟虑,我认为您可以通过让每个具有 table 值的键也成为另一个代理 table 来做到这一点,但是您必须
- 递归地用代理 table 替换所有 table 值,我是
认为每个代理 table 都会包含一些允许的信息
__newindex
为这个代理 table 打印出正确的密钥
- 如果某个键设置为 table 值,则必须递归地将其替换为
proxy tables 之前可以设置实际值
对于本应比这更简单的事情来说,这似乎是太多的工作和复杂的事情。
您需要的是 每个 table 您想要访问的代理 table。执行此操作的最简单方法(虽然不是最高性能)是在访问原始代理时返回一个新的代理-table,并且将返回一个正常的 table:
mt = {}
function mt.__index(self, key)
print('accessing key '..key)
local value = self.proxy[key]
if type(value)=='table' then
return setmetatable({proxy=value}, mt)
else
return value
end
end
function mt.__newindex(self, key, value)
print('setting key '..key..' to value '..tostring(value))
self.proxy[key] = value
end
function setproxy(t)
new_t = {proxy = t}
setmetatable(new_t, mt)
return new_t
end
t = {
a = 1,
b = 2,
c = {
a = 3,
b = 4,
},
}
t = setproxy(t)
t.a = 2 -- Works as expected
t.c.a = 4 -- Also works as expected
性能说明:
由于 Lua 中的 table 被垃圾收集,因此创建新的 table 通常被认为是 "slow"。不过,这仍然是一个观点问题。如果您正在手动编写 运行 的简单脚本,请不要费心优化,它仍然会非常快。如果您正在编写具有数百万次迭代的嵌套循环,或者如果您的代码需要在尽可能短的毫秒内做出响应,那么您应该考虑缓存这些代理 tables, 取决于您的用例。如果您发现您的代码一次又一次地访问相同的代理 tables,每次都创建新的代理-tables,您可以将它们缓存在 proxies table,其中 proxies[table_A] == proxy_to_A
并设置一个 __index
元方法,如果代理不存在则创建该代理。 (此时的权衡是,由于元方法调用,新代理的创建可能会稍微慢一些)。
作为我正在处理的项目的一部分,我希望能够在访问或写入 table 时打印出来,以及 accessed/written 在 [=38 中的内容=].查找此内容,我发现 this,它描述了如何通过使用代理 table 以及 __index
和 [=14 来跟踪何时 table 是 accessed/updated =] 元方法。但是,如果将嵌套 table 用作代理 table,则它们提供的代码无法正确显示正在发生的情况。假设我编写了以下代码,改编自上一个代码:
mt = {}
function mt.__index(self, key)
print('accessing key '..key)
return self.proxy[key]
end
function mt.__newindex(self, key, value)
print('setting key '..key..' to value '..tostring(value))
self.proxy[key] = value
end
function setproxy(t)
new_t = {proxy = t}
setmetatable(new_t, mt)
return new_t
end
t = {
a = 1,
b = 2,
c = {
a = 3,
b = 4,
},
}
t = setproxy(t)
t.a = 2 -- prints "setting key a to value 2" as expected
t.c.a = 4 -- prints "accessing key c", nothing else
这里的问题是 __index
被调用来访问密钥 c
并且它 returns 代理 table 中的一个值,但是没有相同的 metatable,因此它不会记录对 t.c
的写入。我希望第二个作业打印类似 setting key c.a to value 4
的内容,但我不确定从哪里开始实际实现这样的事情。
经过深思熟虑,我认为您可以通过让每个具有 table 值的键也成为另一个代理 table 来做到这一点,但是您必须
- 递归地用代理 table 替换所有 table 值,我是
认为每个代理 table 都会包含一些允许的信息
__newindex
为这个代理 table 打印出正确的密钥 - 如果某个键设置为 table 值,则必须递归地将其替换为 proxy tables 之前可以设置实际值
对于本应比这更简单的事情来说,这似乎是太多的工作和复杂的事情。
您需要的是 每个 table 您想要访问的代理 table。执行此操作的最简单方法(虽然不是最高性能)是在访问原始代理时返回一个新的代理-table,并且将返回一个正常的 table:
mt = {}
function mt.__index(self, key)
print('accessing key '..key)
local value = self.proxy[key]
if type(value)=='table' then
return setmetatable({proxy=value}, mt)
else
return value
end
end
function mt.__newindex(self, key, value)
print('setting key '..key..' to value '..tostring(value))
self.proxy[key] = value
end
function setproxy(t)
new_t = {proxy = t}
setmetatable(new_t, mt)
return new_t
end
t = {
a = 1,
b = 2,
c = {
a = 3,
b = 4,
},
}
t = setproxy(t)
t.a = 2 -- Works as expected
t.c.a = 4 -- Also works as expected
性能说明:
由于 Lua 中的 table 被垃圾收集,因此创建新的 table 通常被认为是 "slow"。不过,这仍然是一个观点问题。如果您正在手动编写 运行 的简单脚本,请不要费心优化,它仍然会非常快。如果您正在编写具有数百万次迭代的嵌套循环,或者如果您的代码需要在尽可能短的毫秒内做出响应,那么您应该考虑缓存这些代理 tables, 取决于您的用例。如果您发现您的代码一次又一次地访问相同的代理 tables,每次都创建新的代理-tables,您可以将它们缓存在 proxies table,其中 proxies[table_A] == proxy_to_A
并设置一个 __index
元方法,如果代理不存在则创建该代理。 (此时的权衡是,由于元方法调用,新代理的创建可能会稍微慢一些)。