metatable是Lua中的重要概念,每個table均可以加上metatable,以改變相應的table的行爲。 函數
-- 聲明一個正常的關係變量 lo_table = {} -- 聲明空元表變量 lo_meta_table = {} -- 爲關係變量t設置元表變量 setmetatable(lo_table, lo_meta_table) -- 獲取一個關係變量的元表變量 getmetatable(lo_table)
上邊的代碼也能夠寫成一行,以下所示 spa
-- setmetatable函數的返回值,就是該函數的第一個參數 lo_table = setmetatable({}, {})
metatable能夠包括任何東西,metatable特有的鍵通常以__開頭,例如__index和__newindex,它們的值通常是函數或其餘table。 3d
lo_table = setmetatable({}, { __index = function(lo_table, key) if key == "foo" then return 0 else return table[key] end end })
這是metatable最經常使用的鍵了。 code
當你經過鍵來訪問table的時候,若是這個鍵沒有值,那麼Lua就會尋找該table的metatable(假定有metatable)中的__index鍵。若是__index包含一個表格,Lua會在表格中查找相應的鍵。 ip
-- 建立元表變量 lo_meta_table = { name = "藍鷗" } -- 設置該元表變量做爲關係變量的 lo_table = setmetatable({}, { __index = lo_meta_table }) -- 打印lo_table變量的姓名 藍鷗 print(lo_table.name) -- 打印lo_table變量年齡 nil print(lo_table.age)
若是__index包含一個函數的話,Lua就會調用那個函數,table和鍵會做爲參數傳遞給函數。 字符串
-- 建立元表變量 lo_meta_table = { name = "藍鷗" , action = function ( param ) -- body if(param == "學生") then print("讓教育迴歸本質") else print("讓藍鷗維護教育") end end } -- 設置該元表變量做爲關係變量的 lo_table = setmetatable({}, { __index = lo_meta_table }) -- 打印lo_table變量的動做 讓教育迴歸本質 print(lo_table.action("學生")) -- 打印lo_table變量的動做 讓藍鷗維護教育 print(lo_table.action("肖浩")) -- 打印lo_table變量年齡 nil print(lo_table.age)
相似__index,__newindex的值爲函數或table,用於按鍵賦值的狀況。 get
-- 建立元表變量 lo_meta_table = {} -- 設置該元表變量做爲關係變量的 lo_table = setmetatable({}, { __newindex = lo_meta_table }) -- 設置lo_table變量的name關鍵字的值 lo_table.name = "藍鷗" -- 打印lo_meta_table元表變量name關鍵字的值值 print(lo_meta_table.name) -- 打印lo_table變量name關鍵字的值 print(lo_table.name)
-- 建立元表變量 lo_meta_table = {} -- 設置該元表變量做爲關係變量的 lo_table = setmetatable({}, { __newindex = function(t, key, value) if type(value) == "number" then rawset(t, key, value * value) else rawset(t, key, value) end end }) -- 設置lo_table變量的name關鍵字的值 lo_table.name = "藍鷗" -- 設置lo_table變量的age關鍵字的值 lo_table.age = 3 -- 打印lo_meta_table元表變量name關鍵字的值值 print(lo_meta_table.name) -- 打印lo_table變量name關鍵字的值 print(lo_table.name) -- 打印lo_meta_table元表變量age關鍵字的值值 print(lo_meta_table.age) -- 打印lo_table變量age關鍵字的值 print(lo_table.age)
上面的代碼中使用了rawget和rawset以免死循環。使用這兩個函數,能夠避免Lua使用__index和__newindex。 string
利用metatable能夠定義運算符,例如+: io
-- 建立重載+號行爲的表變量 lo_table = setmetatable({ 1, 2, 3 }, { __add = function(lo_table, other) new = {} -- 遍歷元素加other for _, v in ipairs(lo_table) do table.insert(new, v + other) end return new end }) -- 進行計算+ lo_table = lo_table + 2 -- 打印獲得的結果 print(lo_table[1]) print(lo_table[2]) print(lo_table[3])
和__index、__newindex不一樣,__mul的值只能是函數。與__mul相似的鍵有: table
__call使得你能夠像調用函數同樣調用table
t = setmetatable({}, { __call = function(t, a, b, c, whatever) return (a + b + c) * whatever end }) local result = t(1, 2, 3, 4) print(result)
最後講下__tostring,它能夠定義如何將一個table轉換成字符串,常常和 print 配合使用,由於默認狀況下,你打印table的時候會顯示 table: 0x7f86f3d04d80 這樣的代碼
lo_table = setmetatable({ 1, 2, 3 }, { __tostring = function(lo_table) sum = 0 for _, v in pairs(lo_table) do sum = sum + v end return "計算的結果是: " .. sum end }) -- prints out "計算的結果是: 6" print(lo_table)
Vector = {} Vector.__index = Vector function Vector.new(x, y) return setmetatable({ x = x or 0, y = y or 0 }, Vector) end -- __call關鍵字 setmetatable(Vector, { __call = function(_, ...) return Vector.new(...) end }) -- + 運算符 function Vector:__add(other) -- ... local result = Vector(self.x + other.x,self.y + other.y) return result end -- __tostring關鍵字 function Vector:__tostring() -- body return "x: " .. self.x .. " y: " .. self.y end a = Vector.new(12, 10) b = Vector(20, 11) c = a + b print(a) print(c)