2016-02-27 37 views
1

我試圖將數據庫實現爲Lua表。使用metatables,這個表將是空的,並且當在表中請求或修改一個項目時,它將返回或修改數據庫中的項目。數據庫本身永遠不會被加載到內存中,除了被請求的部分。它應該通過程序與表格交互(因爲它是一張表格)。該表,因爲它只是一個「前」,所以將修改後的數據保存到數據庫(而不是在表中定義該項)。Lua表作爲數據庫的前端

在沒有表格的表格中,這很容易實現。我試圖讓它與無限深度的多層表一起工作。 (題外話:我正考慮該數據庫Redis的理想情況下,這可能僅用於通過改變基本操作語法任何數據庫或類似數據庫的服務器來實現。)

因爲Lua的元表的行爲,該__newindex方法只有在頂層修改了某些內容(或者如果使用代理創建的)時纔會使用它。即使調用要修改子表中的某些內容,也會在讀取內容時調用__index方法。因此,我試圖編寫一個__index方法,該方法在請求表時返回另一個具有相同行爲的僞代理(表代理數據庫的表而不是另一個表),除了代理用於表/數組/列表內的頂級等,無限深度。我掙扎着。

我的問題是:

  • 先後此之前已經實施?
  • 我應該關注「正確的」 課程系統,而不是我現在正在做的事情嗎?

回答

1

當你創建一個表,只需在假添加一個空表,並設置它的元表:

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

完全避免了直接修改問題