1. 程式人生 > >Lua——3.元表Metatable

Lua——3.元表Metatable

gpo imageview todo 支持 img tex ont ive 三個參數

lua的metatable也是一個普通的表,lua提供metatable的功能,主要有一下幾種作用:

  1. 控制對 table 的訪問
  2. 為 Lua 函數庫提供支持
  3. 重載算數運算符和關系運算符的行為

    1.使用metatable控制對table的訪問

    當查詢table的某個鍵的時候,如果該table的這個鍵沒有值,那麽Lua就會尋找該table的metatable中的__index元方法:如果__index指向一個table,Lua會在此table中查找相應的鍵, 並且,__index也可以指向一個方法

當對table的某個鍵進行賦值時,如果該table存在該字段則為之賦值,若沒有,那麽Lua就會尋找該table的metatable中的__newindex元方法:如果__newindex指向一個table時,Lua會對這個table進行賦值操作,如果__newindex指向一個方法,Lua則會調用該方法

lua中的__index元方法
如果__index包含一個表格,Lua會在此表格中查找相應的鍵。
並且,__index可以指向一個表也可以指向一個方法

__index指向表時:
之前我們需要知道,當我們在一個表中查找一個元素時
首先在該表中查找,有則返回對應值,無則查看該表是否有元表metatable
若無元表則返回nil
有元表時,lua並不是在其元表中查找,而是在其元表的__index域中查找
因此:僅使用setmetatable()方法設置元表,並不能取得對應元表中的元素

BaseClass = {theKey1 = "the string value1"}
--[[
DerivedClass = {}
setmetatable(DerivedClass,BaseClass)
]]--
--註釋的兩句可簡寫為:
DerivedClass = setmetatable({},BaseClass)

res = DerivedClass.theKey1
print(res)

設置對應元表的__index鍵之後:

BaseClass = {theKey1 = "the string value1"}
BaseClass.__index = BaseClass
DerivedClass = setmetatable({},BaseClass)
res = DerivedClass.theKey1
print(res)

也可以換一種簡寫方法:

BaseClass = {theKey1 = "the string value1"}
DerivedClass = setmetatable({},{__index = BaseClass})    --即直接設  AnonymousTable = {__index = BaseClass} 為DerivedClass的元表,查找時可直接在AnonymousTable中的__index域對應的表BaseClass中查找
res = DerivedClass.theKey1
print(res)

技術分享圖片

所以,lua中的繼承可以表示為:

local Car = {}
Car.__index = Car
function Car:new(o)
    o = o or {}
    setmetatable(o,Car)
    return o
end
function Car:run()
    print("Car‘s run func.")
end
--直接調用“父類”中的run方法
Car.run()

local FordCar = Car:new()
--子類調用“父類”中的run方法
FordCar.run()

--重寫fordCar中的run方法
function FordCar:run()
    print("FordCar‘s run func.")
end
--重寫之後調用
FordCar.run()

__index指向一個方法時
__index指向一個方法時,在我們訪問該 table 的不存在的域時,Lua 會嘗試調用 __index 元方法metamethod (__index metamethod 可以接受兩個參數 table 和 key)

local t1 = {}
t1.__index = function(table,key)
    print("call the __index metamethod")
    print("table"..tostring(table))
    print("key"..key)
    return key.." from the __index"
end
--set t1 as t2‘s metatable
local t2 = setmetatable({},t1)
--pass the table and the key to __indexmetamethod
local res = t2.key1
print("the result is :"..res)
print("------------------")
res = t2.key2
print("the result is :"..res)

技術分享圖片

__newindex元方法
如果對 table 的一個不存在的域賦值時,Lua 將檢查 __newindex metamethod:

1.如果 __newindex 為函數,Lua 將調用函數而不是進行賦值(如果 __newindex 為一個函數,它可以接受三個參數 table key value。如果希望忽略 __newindex 方法對 table 的域進行賦值,可以調用 rawset(t, k, v))
2.如果 __newindex 為一個 table,Lua 將對此 table 進行賦值

--file:newindex.lua
local mt = {
    key1 = "key1‘s value"
}

local other = {
    key1 = "the old value"
}

mt.__index = mt
--[[
mt.__newindex = function()
    print "Can not set value"
end
--]]
mt.__newindex = other 

local t = setmetatable({},mt)

t.key1 = "the new value from the table t."
print(t.key1)
--對__newindex指向的table中的key1進行更新操作,但是table t 中仍然沒有鍵key1,進行t.key1的查詢時,查詢的仍然是__index中對應的鍵key1的值
print(other.key1)

技術分享圖片

2. 為 Lua 函數庫提供支持

Lua 庫可以定義和使用 metamethod 來完成一些特定的操作
一個典型的例子是 Lua Base 庫中 __tostring 函數,print 函數會調用此函數進行輸出,調用print時,會檢查並調用 __tostring metamethod

--file:tablelib.lua
local mt = {}
mt.__tostring = function(t)
    return ‘{‘..table.concat(t,‘,‘)..‘}‘
end

local t = {1,2,3}
print(t)
print("-----------------")

setmetatable(t,mt)
print(t)

技術分享圖片

3. 重載算數運算符和關系運算符的行為

//TODO 

Lua——3.元表Metatable