Lua 中元表及元表方法學習

今天花了一些時間學習了Lua元表與元表方法,這裏做個筆記,方便下次理解查看

 

引言:Lua中的每個值都有一套預定義的操作集合,如數字相加等。但無法將兩個table相加,此時可通過元表修改一個值的行爲,使其在面對一個非預定義的操作時執行一個指定操作。
表和完整的用戶數據具有獨立的元表(儘管多個表和用戶數據可共享元表);每種其他類型的所有值共享一個元表。所以,所有數字共享一個元表,字符串也是,等等。

 

元表的作用:通常可以使用元表來修改一個值的行爲, 使其在面對一個非預定的操作時執行一個指定的操作。
元表可以控制對象的數學運算、順序比較、連接、取長、和索引操作的行爲。元表也能定義用戶數據被垃圾收集時調用的函數。Lua給這些操作的每一個都關聯了稱爲事件的特定鍵。當Lua對某值執行其中一個操作時,檢查該值是否含有元表以及相應的事件。如果有,與該鍵關聯的值(元方法)控制Lua如何完成操作。

 

獲取元表和設置元表的方法
 可通過函數getmetatable查詢任何值的元表。
 可通過函數setmetatable替換表的元表。不能從Lua中改變其他類型的元表(除了使用調試庫);必須使用C API才能做到。

 

lua查找一個元素時的規則
1 在表中查找,如果找到,返回該元素,結束查找, 反之繼續
2 判斷該表是否有元表, 如果沒有元表則直接返回nil, 反之繼續
3 判斷元表有沒有__index有沒有元表方法,如果__index方法爲空,則返回nil, 如果__index爲一個函數,則返回該函數的返回值, 如果__index是一個表,則重複1、2、3步驟

 

例子:
local A = {
 a = 100
}

 

local B = {
 b = 50
}

 

setmetatable(B, A)
print(B.a)

 

運行結果: [LUA-print]: nil
分析: 此時查找時步驟1未找到。執行步驟二,存在元表, 繼續執行步驟三, 此時__index方法爲空, 所有直接返回爲nil

 

修改:
local A = {
 a = 100
}

 

local B = {
 b = 50
}

 

A.__index = A;
setmetatable(B, A)
print(B.a)
運行結果:[LUA-print]: 100

 

元方法:
我們稱元表中的鍵爲事件(event), 稱值爲元方法(metamethod). 上面的例子中的index就是一個元方法
每個操作的鍵是由其名字前綴兩個下劃線“__”的字符串;例如,操作“加(add)”的鍵是字符串"__add"。這些操作的語義通過一個Lua函數描述解釋器如何執行操作作了更好的說明。
Lua中支持的元方法
metatable通過其包含的函數來給所掛接的table定義一些特殊的操作,包括:
算數類元方法:
__add: 定義所掛接table的加法操作
__mul: 定義乘法操作
__div: 定義除法操作
__sub: 定義減法操作
__mod: 定義取模操作
__pow:定義乘冪操作
__concat: 定義連接操作(".."運算符)
關係類元方法:
__eq: 定義等於操作
__lt: 定義小於操作
__le: 定義小於等於操作

 

__len: 定義取長度操作 即# 操作
__unm: 定義一元-操作, 即: -table的含義
__tostring: 定義當table作爲tostring()函式之參數被呼叫時的行爲(例如: print(table)時將呼叫tostring(table)作爲輸出結果)
__index: 定義當table中不存在的key值被試圖獲取時的行爲
__newindex: 定義在table中產生新key值時的行爲

 

創建只讀的table
function readOnly(t)
 local proxy = {};
 local mt = {
  __index = t,
  __newindex = function(t, k, v)
   error("attempt to update a read-only table", 2);
  end
 } 
  
 setmetatable(proxy, mt);
 return proxy; 
end

 

local weekdays = readOnly{"Mon", "Tue", "Wed", "Thu", "Fri", "sat", "sun"};
print(weekdays[3]);
weekdays[1] = "Monday"

運行結果:
[LUA-print]: Wed
test.lua:(19): attempt to update a read-only table
Stack Traceback:
 [C]: in function 'error'
 
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章