Lua table 作为数据库的前端
Lua table as frontend to database
我正在尝试将数据库实现为 Lua table。使用 metatables,这个 table 将是空的,当在 table 中请求或修改一个项目时,它将 return 或修改数据库中的项目。数据库本身永远不会加载到内存中,除了被请求的部分。它应该作为 table 与程序交互(因为它是 table)。 table,因为它只是一个 "front",会将修改后的数据保存到数据库中(而不是在 table 中定义该项目)。
在一个没有table的table中,这很容易实现。我试图让它与无限深度的多层 table 一起工作。
(旁白:我正在考虑的数据库是redis。理想情况下,只需更改基本操作语法,就可以为任何数据库或类似数据库的服务器实现。)
由于 Lua 的元tables 的行为,__newindex
方法仅在顶层修改(或创建,如果您'使用代理)。 __index
方法在读取某些内容时被调用,即使该调用是为了修改子 table 中的某些内容。因此,我正在尝试编写一个 __index
方法,当请求 table 时,return 是另一个伪代理(一个 table 代理数据库而不是另一个具有相同行为的 tables),除了代理是针对顶层中的 table/array/list 等,直到一个不确定的深度。我在挣扎。
我的问题是:
- 以前有实施过吗?
- 我应该关注 "proper"
class系统而不是我现在在做什么?
当您创建 table 时,只需在假 table 中添加一个空 table 并将其设置为 metatable:
local fake = {}
do
local lookup = {} --Will be using this to avoid using lots of metatables
local real = {}
local meta
meta = {
__index = function(self,i)
return rawget(lookup[self], i)
end,
__newindex = function(self,i,v)
rawset(lookup[self], i, v)
if type(v) == "table" then
rawset(self, i, setmetatable({},meta))
lookup[self[i]] = v
end
end
}
setmetatable(fake, meta)
lookup[fake] = real
end
fake[1] = "hello"
print(fake[1])
print(rawget(fake, 1))
fake.x = {"hi"}
print(fake.x)
print(rawget(fake, 'x')) --This still prints a table because there actually is one, but in reality it's abiding by our rules
print(fake.x[1])
print(rawget(fake.x, 1))
fake.x.y = "aha"
print(fake.x.y)
print(rawget(fake.x, 'y'))
使用此方法的唯一注意事项是他们可以像这样直接修改数据库:
fake.myvalue = {}
fake.myvalue = 5
另一种方法是边走边换行:
local fake = {}
do
local lookup = {} --Will be using this to avoid using lots of metatables
local cache = {} --will be using to avoid usings tons of new objects
local real = {}
local meta
meta = {
__index = function(self,i)
local val = rawget(lookup[self], i)
if type(val) == "table" then
if cache[val] then
return cache[val]
else
local faker = {}
lookup[faker] = val
cache[val] = faker
return setmetatable(faker, meta)
end
else
return val
end
end,
__newindex = function(self,i,v)
rawset(lookup[self], i, v)
end
}
setmetatable(fake, meta)
lookup[fake] = real
end
fake[1] = "hello"
print(fake[1])
print(rawget(fake, 1))
fake.x = {"hi"}
print(fake.x)
print(rawget(fake, 'x')) --This still prints a table because there actually is one, but in reality it's abiding by our rules
print(fake.x[1])
print(rawget(fake.x, 1))
fake.x.y = "aha"
print(fake.x.y)
print(rawget(fake.x, 'y'))
从而完全避免直接修改问题
我正在尝试将数据库实现为 Lua table。使用 metatables,这个 table 将是空的,当在 table 中请求或修改一个项目时,它将 return 或修改数据库中的项目。数据库本身永远不会加载到内存中,除了被请求的部分。它应该作为 table 与程序交互(因为它是 table)。 table,因为它只是一个 "front",会将修改后的数据保存到数据库中(而不是在 table 中定义该项目)。
在一个没有table的table中,这很容易实现。我试图让它与无限深度的多层 table 一起工作。 (旁白:我正在考虑的数据库是redis。理想情况下,只需更改基本操作语法,就可以为任何数据库或类似数据库的服务器实现。)
由于 Lua 的元tables 的行为,__newindex
方法仅在顶层修改(或创建,如果您'使用代理)。 __index
方法在读取某些内容时被调用,即使该调用是为了修改子 table 中的某些内容。因此,我正在尝试编写一个 __index
方法,当请求 table 时,return 是另一个伪代理(一个 table 代理数据库而不是另一个具有相同行为的 tables),除了代理是针对顶层中的 table/array/list 等,直到一个不确定的深度。我在挣扎。
我的问题是:
- 以前有实施过吗?
- 我应该关注 "proper" class系统而不是我现在在做什么?
当您创建 table 时,只需在假 table 中添加一个空 table 并将其设置为 metatable:
local fake = {}
do
local lookup = {} --Will be using this to avoid using lots of metatables
local real = {}
local meta
meta = {
__index = function(self,i)
return rawget(lookup[self], i)
end,
__newindex = function(self,i,v)
rawset(lookup[self], i, v)
if type(v) == "table" then
rawset(self, i, setmetatable({},meta))
lookup[self[i]] = v
end
end
}
setmetatable(fake, meta)
lookup[fake] = real
end
fake[1] = "hello"
print(fake[1])
print(rawget(fake, 1))
fake.x = {"hi"}
print(fake.x)
print(rawget(fake, 'x')) --This still prints a table because there actually is one, but in reality it's abiding by our rules
print(fake.x[1])
print(rawget(fake.x, 1))
fake.x.y = "aha"
print(fake.x.y)
print(rawget(fake.x, 'y'))
使用此方法的唯一注意事项是他们可以像这样直接修改数据库:
fake.myvalue = {}
fake.myvalue = 5
另一种方法是边走边换行:
local fake = {}
do
local lookup = {} --Will be using this to avoid using lots of metatables
local cache = {} --will be using to avoid usings tons of new objects
local real = {}
local meta
meta = {
__index = function(self,i)
local val = rawget(lookup[self], i)
if type(val) == "table" then
if cache[val] then
return cache[val]
else
local faker = {}
lookup[faker] = val
cache[val] = faker
return setmetatable(faker, meta)
end
else
return val
end
end,
__newindex = function(self,i,v)
rawset(lookup[self], i, v)
end
}
setmetatable(fake, meta)
lookup[fake] = real
end
fake[1] = "hello"
print(fake[1])
print(rawget(fake, 1))
fake.x = {"hi"}
print(fake.x)
print(rawget(fake, 'x')) --This still prints a table because there actually is one, but in reality it's abiding by our rules
print(fake.x[1])
print(rawget(fake.x, 1))
fake.x.y = "aha"
print(fake.x.y)
print(rawget(fake.x, 'y'))
从而完全避免直接修改问题