天天看點

Lua面向對象程式設計 (__index、__newindex、__call、__add)

Lua面向對象程式設計

1、__index學習

【前置知識】

setmatatable:設定元表

setmetatable(table1, metatable)

metatable裡一般實作__index、__newindex、__add等元方法實作對table的某種操作

當__index為表時

通過鍵值通路table時,如果沒有這個鍵,那麼Lua就會尋找table的metatable中__index表裡的key鍵

性質很像繼承關系的父親

【代碼】

t1 = {area = 0}

t2 = setmetatable(t1, {__index = {width = 1}})
-- 此時t1 等價t2 有相同的位址空間
print(t1.area)
print(t1.width)
t1.area = 2
print(t2.area)
print(t2.width)
t2.width = 2
print(t1.area)
print(t1.width)      

【運作結果】

Lua面向對象程式設計 (__index、__newindex、__call、__add)

__index實作繼承關系

【代碼】

--繼承關系
Shape = {area = 0}
function Shape:new(o, side)
  o = o or {}
  setmetatable(o, self)
  self.__index = self  --保持繼承鍊,不加此行, t1就沒有__index元方法,下面的t2 = it:new({}, 4)會報錯
  side = side or 0
  o.area = side * side
  return o
end

t1 = Shape:new({key1 = 1}, 3)
print("t1.area:", t1.area)
print("t1.key1:", t1.key1)
t2 = t1:new({key2 = 2}, 4)
print("t2.key1:", t2.key1)
print("t2.key2:", t2.key2)
t3 = t2:new({key3 = 3}, 5)

print("t3.key1:", t3.key1)
print("t3.key2:", t3.key2)
print("t3.key3:", t3.key3)      

【運作結果】

Lua面向對象程式設計 (__index、__newindex、__call、__add)

當__index為函數時

通過table.key查找時,會将table和key作為參數傳給函數

【代碼】

t = setmetatable({key1 = "hsj"}, {__index = function(table, key)
  if key == 'key2' then
    return 'yes'
  else
    return 'no'
  end
end})

print(t.key2)      

【運作結果】

Lua面向對象程式設計 (__index、__newindex、__call、__add)

2、__newindex學習

正常的table當對表中一個不存的key進行指派,會産生一個新的key值儲存。當用了__newindex後,則table不會産生新的key值,而對metatable産生新的key儲存

【代碼】

t = {}
print("t.key:", t.key)
t1 = setmetatable({},{__newindex = t})
t1.key = 1
print("t1.key:", t1.key)
print("t.key:",t.key)      

【運作結果】

Lua面向對象程式設計 (__index、__newindex、__call、__add)
__index和__newindex混合使用

【代碼】

t2 = {}
t = setmetatable({key1 = "hsj"}, {__index = function(table, key)
  if key == 'key2' then
    return 'yes'
  else
    return 'no'
  end
end,
__newindex = t2
})

t.key2 = 2
print("t2.key2:", t2.key2)
print("t.key2:", t.key2)      

【運作結果】

Lua面向對象程式設計 (__index、__newindex、__call、__add)

【私密性】

相當于private

__index和__newindex建立一個隻讀的table

--隻讀table

function readOnly(t)
  local answer = {}
  local mt =  {
    __index = t,
    __newindex = function(t, k, v)
      error("attempt to update a read-only table", 2)
    end
  }

  setmetatable(answer, mt)
  return answer
end

t1 = {1, 2, 3, 4, 5}

t2 = readOnly(t1)

print(t2[1])

t2[1] = 5   --無法修改      

__call

__call 元方法在 Lua 調用一個值時調用。

self或表名均可

【代碼】

mytable = setmetatable({10}, {
__call = function(self, value)
  print("value:", value)
end
})
print(mytable(10))

mytable = setmetatable({10}, {
__call = function(mytable, value)
  print("value:", value)
end
})
print(mytable(10))      

【運作結果】

Lua面向對象程式設計 (__index、__newindex、__call、__add)
重載__add元方法
--隻讀table

t = setmetatable({1, 2, 3},{
  __add = function(self, newtable)
    len1 = #self
    len2 = #newtable
    sum = 0
    for i=1, len1 do
      sum = sum + self[i]
    end
    for i=1, len2 do
      sum = sum + newtable[i]
    end
    return sum

  end
})


t1 = {2,3,4}

answer = t + t1
print("answer:", answer)      

其他類似的元方法

__add(a, b)                     對應表達式 a + b

__sub(a, b)                     對應表達式 a - b

__mul(a, b)                     對應表達式 a * b

__div(a, b)                     對應表達式 a / b

__mod(a, b)                     對應表達式 a % b

__pow(a, b)                     對應表達式 a ^ b

__unm(a)                        對應表達式 -a

__concat(a, b)                  對應表達式 a .. b

__len(a)                        對應表達式 #a

__eq(a, b)                      對應表達式 a == b

__lt(a, b)                      對應表達式 a < b