Lua模塊與元表(Metatable)

一、模塊(module)

模塊類似于一個封裝庫,可以把一些公用的代碼放在一個文件里,以 API 接口的形式在其他地方調(diào)用,有利于代碼的重用和降低代碼耦合度。
Lua 的模塊是由變量、函數(shù)等已知元素組成的 table,因此創(chuàng)建一個模塊很簡單,就是創(chuàng)建一個 table,然后把需要導(dǎo)出的常量、函數(shù)放入其中,最后返回這個 table 就行。以下為創(chuàng)建自定義模塊 module.lua。

--文件名為module,lua
--定義一個modul的模塊
module={}
--定義一個常量
module.var="Lian"

--局部函數(shù),相當(dāng)于C#中的私有函數(shù),不能在外界調(diào)用
local function func1()
 print("這是一個局部私有函數(shù)")
end

--定義全局一個函數(shù)
function module.func2()
func1()
print("這是一個全局公有函數(shù)")
end

return module

由上可知,模塊的結(jié)構(gòu)就是一個 table 的結(jié)構(gòu),因此可以像操作調(diào)用 table 里的元素那樣來操作調(diào)用模塊里的常量或函數(shù)。
上面的 func1 聲明為程序塊的局部變量,即表示一個私有函數(shù),因此是不能從外部訪問模塊里的這個私有函數(shù),必須通過模塊里的公有函數(shù)來調(diào)用.

下面再去創(chuàng)建usermodule.lua文件去調(diào)用模塊中的函數(shù)和變量,使用require 函數(shù)
Lua提供了一個名為require的函數(shù)用來加載模塊。要加載一個模塊,只需要簡單地調(diào)用就可以了。

--require "模塊名"
m= require "module"

print(m.var)--調(diào)用模塊中的變量
m.func2()--調(diào)用模塊中的全局函數(shù)

最后運(yùn)行可以看到輸出結(jié)果調(diào)用了module模塊中的函數(shù)和變量

運(yùn)行結(jié)果:
Lian
這是一個局部私有函數(shù)
這是一個全局公有函數(shù)
二、元表(Metatable)

在 Lua table 中我們可以訪問對應(yīng)的key來得到value值,但是卻無法對兩個 table 進(jìn)行操作。
因此 Lua 提供了元表(Metatable),允許我們改變table的行為,每個行為關(guān)聯(lián)了對應(yīng)的元方法。
例如,使用元表我們可以定義Lua如何計算兩個table的相加操作a+b。
有兩個很重要的函數(shù)來處理元表:

setmetatable(table,metatable): 
對指定table設(shè)置元表(metatable),如果元表(metatable)中存在__metatable鍵值,setmetatable會失敗 。

getmetatable(table): 返回對象的元表(metatable)。

如何對指定的表設(shè)置元表:

mytable={"Lua","Java","C","C#","C++"}--普通表
--使用__metatable可以保護(hù)元表,禁止用戶訪問元表中的成員或者修改
mymetatable={__metatable="lock"}--元表  元表擴(kuò)展了普通表的行為

mytable=setmetatable(mytable,mymetatable)--給指定的表設(shè)定元表
print(getmetatable(mytable))--返回普通表的元表

輸出結(jié)果:lock
__index 元方法
是 metatable 最常用的鍵。
當(dāng)你通過鍵來訪問 table 的時候,如果這個鍵沒有值,那么Lua就會尋找該table的metatable(假定有metatable)中的__index 鍵。如果__index包含一個表格,Lua會在表格中查找相應(yīng)的鍵。

如果__index包含一個函數(shù)的話,Lua就會調(diào)用那個函數(shù),table和鍵會作為參數(shù)傳遞給函數(shù)。
__index 元方法查看表中元素是否存在,如果不存在,返回結(jié)果為 nil;如果存在則由 __index 返回結(jié)果。

--__index用來處理訪問到的索引不存在的時候怎么辦
mytable={"Lua","Java","C","C#","C++"}--普通表
mymetatable={
  __index=function (tab,key)
      return "JavaScript"
   end
  }--元表  元表擴(kuò)展了普通表的行為

mytable=setmetatable(mytable,mymetatable)--給指定的表設(shè)定元表
print(mytable[10])--訪問表中不存在的鍵時會執(zhí)行元表中的匿名函數(shù)

輸出結(jié)果:JavaScript
__newindex 元方法
__newindex 元方法用來對表更新,__index則用來對表訪問 。
當(dāng)你給表的一個缺少的索引賦值,解釋器就會查找__newindex 元方法:如果存在則調(diào)用這個函數(shù)而不進(jìn)行賦值操作。

--__newindex當(dāng)我們對表的數(shù)據(jù)進(jìn)行修改的時候,當(dāng)我們給表添加新的鍵值對的時候會起作用
mytable={"Lua","Java","C","C#","C++"}--普通表
mymetatable={
  __newindex=function (tab,key,value)
      print("我們要修改的key為:"..key.."把這個key值修改為:"..value)

    rawset(tab,key,value)--設(shè)置鍵值對,添加輸入進(jìn)來的鍵值對
   end
  }--元表  元表擴(kuò)展了普通表的行為
  mytable=setmetatable(mytable,mymetatable)--給指定的表設(shè)定元表
  mytable[6]="JavaScript"
  print(mytable[6])

輸出結(jié)果:

我們要修改的key為:6把這個key值修改為:JavaScript
JavaScript

為表添加操作符
__add元方法:當(dāng)兩個表相加時實(shí)現(xiàn)相應(yīng)的函數(shù)方法

mytable={"Lua","Java","C","C#","C++"}--普通表
mymetatable={
--兩表相加將新表中的元素添加到mytable中去
  __add=function (tab,newtab)
     local mi=0
     for k,v in pairs(tab) do
        if (k>mi)then
            mi=k
        end
     end

     for k,v in pairs(newtab) do
        mi=mi+1
        table.insert(tab,mi,v)
     end
     return tab
   end
  }--元表  元表擴(kuò)展了普通表的行為

  mytable=setmetatable(mytable,mymetatable)--給指定的表設(shè)定元表
  
  newtab={"PHP","Phthon"}
  
  --其中只要有一個表設(shè)置了元表都可以實(shí)現(xiàn)加法
  v=mytable+newtab

  
  for k,v in pairs(v) do
     print(k,v)
  end

輸出結(jié)果:

1   Lua
2   Java
3   C
4   C#
5   C++
6   PHP
7   Phthon

其他操作符:

image.png

__call元方法
__call 元方法在 Lua 調(diào)用一個值時調(diào)用。也就是說當(dāng)我們把表當(dāng)作函數(shù)來使用的時候調(diào)用,例如:mytable(25)

mytable={"Lua","Java","C","C#","C++"}
 mymetatable={
 __call=function (tab,arg)
     print("Call元方法_"..arg)
 end
 }
  mytable=setmetatable(mytable,mymetatable)
 mytable("涼")

輸出結(jié)果:Call元方法_涼
__tostring 元方法
__tostring 元方法用于修改表的輸出行為。表示在使用輸出print(table)的時候會調(diào)用元表中的函數(shù),如下

mytable={"Lua","Java","C","C#","C++"}
 mymetatable={
 __tostring=function (tab)
      local str=""
      for k,v in pairs(tab) do
        str=str..v..","
      end
     return str
 end
 }
  mytable=setmetatable(mytable,mymetatable)

 print(mytable)

輸出結(jié)果:

Lua,Java,C,C#,C++,
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容