1. 程式人生 > >lua元表的相關知識

lua元表的相關知識

setmetatable()和getmetatable():


local a=8
local b = "s"
local t = {1,2}

--在Lua程式碼中,只能設定table的元表。若要設定其它型別的值得元表,則必須通過C程式碼來完成
--對於字串,標準的字串程式庫為所有的字串都設定了一個元表,而其它型別在預設情況下都沒有元表
print(getmetatable(t))  --輸出nil
print(getmetatable(b))  --輸出table: 0042EA68
print(getmetatable(a))  --輸出nil

local t2 = {}
setmetatable(t,t2) --將t2設定為t的元表
print(getmetatable(t))  --輸出table: 0026B120

--setmetatable(a,t2)
--print(getmetatable(a)) --報錯  /在 Lua 程式碼中,通過呼叫setmetatable 來設定且只能設定 table 的元表
setmetatable(b,t2)
print(getmetatable(b))  --報錯   /在 Lua 程式碼中,通過呼叫setmetatable 來設定且只能設定 table 的元表

元方法__metatable:


Set = {}
local mt = {}

--根據引數列表中的值建立一個新的集合
function Set.New(T)
    local set = {}
    setmetatable(set,mt)
    for _ ,v in pairs(T) do
        set[v]=true
    end
    ----使用__metatable可以保護元表,禁止使用者訪問元表中的成員或者修改元表
    mt.__metatable = "can not get the metatable"
    return set
end

local tb = Set.New({1,2,3}) --將mt設定為tb的元表
print(tb)

print(getmetatable(tb))  --輸出can not get the metatable
local test = {1,2}
setmetatable(test,mt)
print(getmetatable(test))   --輸出can not get the metatable
--setmetatable(tb,{}) --報錯cannot change a protected metatable  輸出"can not get the metatable"


元方法__add:


--------------元方法  __add

local mt ={}

--定義一個元方法
mt.__add = function (t1,t2)
    local temp = {}
    for i, v in pairs(t1) do
        table.insert(temp,v)
    end
    for i, v in pairs(t2) do
        table.insert(temp,v)
    end
    return temp
end

local t1 = {1,2,3}
local t2 = {3,5}
setmetatable(t1,mt) --設定mt為t1的元表
local t3 = t1+t2  --將兩個table相加

for i, v in pairs(t3) do
    print(v)  --輸出1 2 3 3 5
end

--程式執行順序:
--lua中兩個table原本是無法做相加操作的,但是可以通過__add元方法實現
--先查詢t1中是否有對應的元表,若有看看是否定義了__add元方法。如果有則運算
--沒有則查詢t2中是否有對應的元表,再看看是否定義了__add元方法,有則運算,沒有報錯

元方法__index:

---
windows = {}
windows.default = {x=0,y=0,color = {r=255,g=255,b=125}}
windows.mt = {} --建立元表

--宣告new函式
function windows.new(o)
    setmetatable(o,windows.mt)
    return o
end

--定義__index元方法  對應的是一個有引數的函式
windows.mt.__index = function(table,key)
    return windows.default[key]
end
local www = windows.new({x=10,z=30})
--print(www.x)  --輸出10
--print(www.y)  --輸出 0
--print(www.color.r)  --輸出 255

other1 = {hhh = 666}
other2  ={mmm=333,ppp=999,hhh=5555}
setmetatable(other2,other1)
--定義__index元方法  對應的是一個table
other1.__index =other1
print(other2.hhh)  --輸出666
print(other2.jjj)   --輸出nil

--定義__index元方法  對應的是一個沒有引數的函式
--function setDefault(tb,defaultValue)
--    local mt = {__index = function()return defaultValue end}
--    setmetatable(tb,mt)
--end
--tb1 = {x=10,y=20}
--setDefault(tb1,100)
--print(tb1.x)   --輸出 10
--print(tb1.z)   --輸出100
--print(tb1.k)   --輸出100

--程式執行順序:
--通過鍵來訪問table時,如果table中沒有這個鍵,那麼lua就會查詢該table是否有元表
--元表中是否定義了__index元方法,若__index對應的是一個函式,那麼lua就會呼叫這個函式,
--table和鍵作為引數傳給函式;
--若__index對應的是一個table,那麼lua就在這個table中查詢對應的鍵

元方法__newindex:

---
local smartMan = {
    name = "king",
    sayhello = function()
        print("你媽喊你回家吃飯")
    end
}
local t1 = {kkk = "7"}
--t1.name = "5"

local mt ={
    --__index = smartMan,
    __newindex = function(table,key,value)
        print("你媽喊你回家拖地")
        rawset(table,key,value)
    end,
}
setmetatable(t1,mt)

t1.kkk = 6
print(t1.kkk) -- 輸出 6

t1.kkk = "5"
t1.ggg = "000"  --新增一個索引
print(t1.kkk) --輸出   你媽喊你回家拖地    5
--  __newindex元方法用於索引更新

rawget()和rawset():


--rawset(table,index,value)
--在不呼叫元表的情況下,給table[index]賦值為value
--就是說就算該table有元表,這個函式也會讓元方法失去作用
local m1 = {x=1,y=2}
local m2 = {z=3}
setmetatable(m1,m2)
m2.__index = m2

print(m1.z) --輸出3

rawset(m1,"z",5)
print(m1.z)  --輸出 5

--rawget(table,index)
--不呼叫元表,獲取table真正的值table[index]
local m3 = {x=1,y=2}
local m4 = {x=6,z=8}
setmetatable(m3,m4)
m4.__index = m4
print(m3.x) --輸出 1
print(m3.z) --輸出 8

local zhi= rawget(m3,"z")
print(zhi) --輸出nil

元方法總彙: 在這裡插入圖片描述 後續若有在專案中碰到其他元方法再補上。