【Lua特性】Metatable(元表)
阿新 • • 發佈:2018-12-12
__index 元方法
主要用於table的查詢,其可為table或function.
__newindex 元方法
主要用於table的更新(賦值),其可為table或function.
local parent = { atk = 1 } local child = { hp = 2 } parent.__index = parent setmetatable(child, parent) print(child.atk) -- ot:1 print(child.hp) -- ot:2 parent.__newindex = function ( t, k ,v ) if k == "atk" then parent[k] = v * 2 end end child.atk = 3 child.hp = 4 print(child.atk) -- ot:6 print(child.hp) -- ot:4 parent.__index = nil print(child.atk) -- ot:nil print(child.hp) -- ot:4
Lua查詢一個表元素時的規則,其實就是如下3個步驟:
1. 在表中查詢,如果找到,返回該元素,找不到則繼續 2. 判斷該表是否有元表,如果沒有元表,返回nil,有元表則繼續。 3. 判斷元表有沒有__index方法,如果__index方法為nil,則返回nil;如果__index方法是一個表,則重複1、2、3;如果__index方法是一個函式,則返回該函式的返回值。
操作符
local v1 = { x = 1, y = 2 } local v2 = { x = 3, y = 4 } local meta = {} meta.__add = function ( lhs, rhs ) local ret = {} ret.x = lhs.x + rhs.x ret.y = lhs.y + rhs.y return ret end setmetatable(v1, meta) setmetatable(v2, meta) local v3 = v1 + v2 print(v3.x, v3.y) -- 4, 6
模式 | 描述 |
---|---|
__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 |
__eq(a, b) | a == b |
__lt(a, b) | a < b |
__le(a, b) | a <= b |
__call 元方法
把table當做函式呼叫
local meta = {} meta.__call = function ( t1, t2 ) local sum = 0 for _, v in pairs(t1) do sum = sum + v end for _, v in pairs(t2) do sum = sum + v end return sum end local newTable = { 1, 2 } setmetatable(newTable, meta) -- 上面兩行,可寫成 local newTable = setmetatable({ 1, 2 }, meta) print(newTable({3, 4, 5})) -- 15
__tostring
local meta = {}
meta.__tostring = function ( t )
local ret = ""
for _, v in pairs(t) do
ret = ret .. " " .. v
end
return "表元素: " .. ret
end
local newTable = setmetatable({1, 2, 3, 4}, meta)
print(newTable) -- 表元素: 1 2 3 4
用法例項:
local Stack = { data = {} }
function Stack:new()
self.__index = self
return setmetatable({ data = {} }, self)
end
function Stack:add(name, age)
table.insert(self.data, {["name"] = name, ["age"] = age})
end
function Stack:get( name )
for k, v in pairs(self.data) do
if v.name == name then
return v, k
end
end
return nil, 0
end
function Stack:getByIdx( idx )
return self.data[idx]
end
function Stack:size()
return #self.data
end
local studentList = Stack:new()
studentList:add("小明", 10)
studentList:add("小紅", 12)
studentList:add("小蘭", 11)
local s1 = studentList:get("小蘭")
print(s1.name .. " " .. s1.age) -- 小蘭 11
print("學生數量: " .. studentList:size()) -- 學生數量: 3
--預設值
function setDefault ( t , default )
local mt = {}
mt.__index = function ( )
return default
end
setmetatable(t , mt)
end
local v = { x = 1 ,y = 2 }
print(v.x , v.y , v.z) -- 1 2 nil
-- 設定預設值
setDefault(v, 0)
print(v.x , v.y , v.z) -- 1 2 0
--只讀屬性
function setReadOnly ( t )
local mt = {}
mt.__index = t
mt.__newindex = function ( )
print("it's a readOnly table")
end
return setmetatable({} , mt)
end
local data = setReadOnly({ 1, 2, 3, 4 })
print(1) -- 1
data[1] = 11 -- it's a readOnly table