lua元表詳解

2021-09-27 02:38:20 字數 4990 閱讀 7780

元表是用來定義對table或userdata操作方式的表

local t1 = 

local t2 =

local t3 = t1 + t2

我們直接對兩個table執行+運算,會報錯

lua: /usercode/file.lua:3: attempt to perform arithmetic on local 't1' (a table value)

因為程式不知道如何對兩個表執行+執行,這時候就需要通過元表來定義如何執行t1的+運算,有點類似於c語言中的運算子過載。

local mt = {}

--定義mt.__add元方法(其實就是元表中乙個特殊的索引值)為將兩個表的元素合併後返回乙個新錶

mt.__add = function(t1,t2) local temp = {} for _,v in pairs(t1) do table.insert(temp,v) end for _,v in pairs(t2) do table.insert(temp,v) end return temp end local t1 = local t2 = --設定t1的元表為mt setmetatable(t1,mt) local t3 = t1 + t2 --輸出t3 local st = "" print(st)

結果為:

因為程式在執行t1+t2的時候,會去呼叫t1的元表mt的__add元方法進行計算。

具體的過程是:

1.檢視t1是否有元表,若有,則檢視t1的元表是否有__add元方法,若有則呼叫。

2.檢視t2是否有元表,若有,則檢視t2的元表是否有__add元方法,若有則呼叫。

3.若都沒有則會報錯。

所以說,我們通過定義了t1元表的__add元方法,達到了讓兩個表通過+號來相加的效果

函式描述

__add

運算子 +

__sub

運算子 -

__mul

運算子 *

__ div

運算子 /

__mod

運算子 %

__unm

運算子 -(取反)

__concat

運算子 ..

__eq

運算子 ==

__lt

運算子 <

__le

運算子 <=

__call

當函式呼叫

__tostring

轉化為字串

__index

呼叫乙個索引

__newindex

給乙個索引賦值

由於那幾個運算子使用類似,所以就不單獨說明了,接下來說 __call, __tostring, __index, __newindex四個元方法。

__call可以讓table當做乙個函式來使用。

local mt = {}

--__call的第一引數是表自己

mt.__call = function(mytable,...) --輸出所有引數 for _,v in ipairs do print(v) end end t = {} setmetatable(t,mt) --將t當作乙個函式呼叫 t(1,2,3)

結果:

123

__tostring可以修改table轉化為字串的行為

local mt = {}

--引數是表自己

mt.__tostring = function(t) local s = "" return s end t = --直接輸出t print(t) --將t的元表設為mt setmetatable(t,mt) --輸出t print(t)

結果:

table: 0x14e2050

呼叫table的乙個不存在的索引時,會使用到元表的__index元方法,和前幾個元方法不同,__index可以是乙個函式也可是乙個table。

作為函式:

將表和索引作為引數傳入__index元方法,return乙個返回值

local mt = {}

--第乙個引數是表自己,第二個引數是呼叫的索引

mt.__index = function(t,key) return "it is "..key end t = --輸出未定義的key索引,輸出為nil print(t.key) setmetatable(t,mt) --設定元表後輸出未定義的key索引,呼叫元表的__index函式,返回"it is key"輸出 print(t.key)

結果:

nil

it is key

作為table:

查詢__index元方法表,若有該索引,則返回該索引對應的值,否則返回nil

local mt = {}

mt.__index =

t = --輸出未定義的key索引,輸出為nil print(t.key) setmetatable(t,mt) --輸出表中未定義,但元表的__index中定義的key索引時,輸出__index中的key索引值"it is key" print(t.key) --輸出表中未定義,但元表的__index中也未定義的值時,輸出為nil print(t.key2)

結果:

nil

it is key

nil

當為table中乙個不存在的索引賦值時,會去呼叫元表中的__newindex元方法

作為函式

__newindex是乙個函式時會將賦值語句中的表、索引、賦的值當作引數去呼叫。不對錶進行改變

local mt = {}

--第乙個引數時表自己,第二個引數是索引,第三個引數是賦的值

mt.__newindex = function(t,index,value) print("index is "..index) print("value is "..value) end t = setmetatable(t,mt) --輸出表中已有索引key的值 print(t.key) --為表中不存在的newkey索引賦值,呼叫了元表的__newindex元方法,輸出了引數資訊 t.newkey = 10 --表中的newkey索引值還是空,上面看著是乙個賦值操作,其實只是呼叫了__newindex元方法,並沒有對t中的元素進行改動 print(t.newkey)

結果:

it is key

index is newkey

value is 10

nil

作為table

__newindex是乙個table時,為t中不存在的索引賦值會將該索引和值賦到__newindex所指向的表中,不對原來的表進行改變。

local mt = {}

--將__newindex元方法設定為乙個空表newtable

local newtable = {}

mt.__newindex = newtable

t = {}

setmetatable(t,mt) print(t.newkey,newtable.newkey) --對t中不存在的索引進行負值時,由於t的元表中的__newindex元方法指向了乙個表,所以並沒有對t中的索引進行賦值操作將,而是將__newindex所指向的newtable的newkey索引賦值為了"it is newkey" t.newkey = "it is newkey" print(t.newkey,newtable.newkey)

結果:

nil nil

nil it is newkey

有時候我們希望直接改動或獲取表中的值時,就需要rawget和rawset方法了。

rawget可以讓你直接獲取到表中索引的實際值,而不通過元表的__index元方法。

local mt = {}

mt.__index =

t = {}

setmetatable(t,mt)

print(t.key) --通過rawget直接獲取t中的key索引 print(rawget(t,"key"))

結果:

it is key

nil

rawset可以讓你直接為表中索引的賦值,而不通過元表的__newindex元方法。

local mt = {}

local newtable = {}

mt.__newindex = newtable

t = {}

setmetatable(t,mt)

print(t.newkey,newtable.newkey) --通過rawset直接向t的newkey索引賦值 rawset(t,"newkey","it is newkey") print(t.newkey,newtable.newkey)

結果:

nil nil

it is newkey nil

通過為table設定元表可以在lua中實現物件導向程式設計。

通過對userdata和元表可以實現在lua中對c中的結構進行物件導向式的訪問。

標籤: 

lua

lua中的元表詳解

近日開始頻繁使用lua,發現身邊有很多同學對元表的理解不太正確,於是把這塊東西理了一下,分享出來 lua的表本質其實是個類似hashmap的東西,其元素是很多的key value對,如果嘗試訪問了乙個表中並不存在的元素時,就會觸發lua的一套查詢機制,也是憑藉這個機制來模擬了類似 繼承 的行為 舉例...

詳解Lua中的元表概念

有跡象表明,在處理metatables其中包括使用了兩種重要的方法,讓我們先來看看如何設定乙個表作為另乙個元表。它如下所示。複製 如下 mytable mymetatable setmetatable mytable,mymetatable 上面的 可以在乙個單一的行被表示為如下所示。複製 如下 m...

Lua元表和元表方法

今天學習lua中的元表,書上講的太難懂了,網上搜尋教程也將的模模糊糊,搜了一會總結了一下經驗,跟大家分享一下,希望對您有所幫助。如何設定元表?local t local mt getmetatable t nil setmetatable t,mt 將t1設定為t的元表 getmetatable t...