【问题标题】:Lua table as frontend to databaseLua 表作为数据库的前端
【发布时间】:2023-03-08 15:06:01
【问题描述】:

我正在尝试将数据库实现为 Lua 表。使用元表,这个表会是空的,当一个项目在表中被请求或修改时,它会返回或修改数据库中的项目。数据库本身永远不会加载到内存中,除了被请求的部分。它应该由程序作为一个表进行交互(因为它是一个表)。该表,因为它只是一个“前端”,所以会将修改后的数据保存到数据库中(而不是在表中定义该项目)。

在没有表格的表格中,这很容易实现。我试图让它与一个无限深度的多层表一起工作。 (顺便说一句:我正在考虑的数据库是redis。理想情况下,只需更改基本操作语法,就可以为任何数据库或类似数据库的服务器实现。)

由于 Lua 元表的行为,__newindex 方法仅用于在顶层修改某些内容(或创建,如果您使用代理)。 __index 方法在读取某些内容时调用,即使该调用是要修改子表中的某些内容。正因为如此,我正在尝试编写一个__index 方法,当请求一个表时,它返回另一个具有相同行为的伪代理(代理数据库而不是另一个表的表),除了代理用于顶层中的表/数组/列表等,深度不定。我在挣扎。

我的问题是:

  • 以前是否已实施?
  • 我是否应该专注于“正确” 类系统而不是我现在在做什么?

【问题讨论】:

    标签: lua redis lua-table


    【解决方案1】:

    创建表时,只需在 fake 中添加一个空表并将其设置为元表:

    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'))
    

    完全避免了直接修改问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-26
      • 1970-01-01
      • 2015-08-19
      • 2010-09-05
      • 1970-01-01
      • 2010-10-12
      • 2012-06-28
      • 2017-04-22
      相关资源
      最近更新 更多