復(fù)制代碼 代碼如下:
function createCountdownTimer(second)
local ms=second * 1000;
local function countDown()
ms = ms - 1;
return ms;
end
return countDown;
end
timer1 = createCountdownTimer(1);
for i=1,3 do
print(timer1());
end
print("------------");
timer2 = createCountdownTimer(1);
for i=0,2 do
print(timer2());
end
復(fù)制代碼 代碼如下:
999
998
997
------------
999
998
997
Upvalue:一個(gè)函數(shù)所使用的定義在它的函數(shù)體之外的局部變量(external localvariable)稱為這個(gè)函數(shù)的upvalue。
在前面的代碼中,函數(shù)countDown使用的定義在函數(shù)createCountdownTimer中的局部變量ms就是countDown的upvalue,但ms對createCountdownTimer而言只是一個(gè)局部變量,不是upvalue。Upvalue是Lua不同于C/C++的特有屬性,需要結(jié)合代碼仔細(xì)體會(huì)。
函數(shù)閉包:一個(gè)函數(shù)和它所使用的所有upvalue構(gòu)成了一個(gè)函數(shù)閉包。
閉包是一個(gè)內(nèi)部函數(shù),它可以訪問一個(gè)或者多個(gè)外部函數(shù)的外部局部變量。每次閉包的成功調(diào)用后這些外部局部變量都保存他們的值(狀態(tài))。當(dāng)然如果要?jiǎng)?chuàng)建一個(gè)閉包必須要?jiǎng)?chuàng)建其外部局部變量。所以一個(gè)典型的閉包的結(jié)構(gòu)包含兩個(gè)函數(shù):一個(gè)是閉包自己;另一個(gè)是工廠(創(chuàng)建閉包的函數(shù))。迭代器需要保留上一次成功調(diào)用的狀態(tài)和下一次成功調(diào)用的狀態(tài),也就是他知道來自于哪里和將要前往哪里。閉包提供的機(jī)制可以很容易實(shí)現(xiàn)這個(gè)任務(wù)。
Lua函數(shù)閉包與C函數(shù)的比較:Lua函數(shù)閉包使函數(shù)具有保持它自己的狀態(tài)的能力,從這個(gè)意義上說,可以與帶靜態(tài)局部變量的C函數(shù)相類比。但二者有顯著的不同:對Lua來說,函數(shù)是一種基本數(shù)據(jù)類型——代表一種(可執(zhí)行)對象,可以有自己的狀態(tài);但是對帶靜態(tài)局部變量的C函數(shù)來說,它并不是C的一種數(shù)據(jù)類型,更不會(huì)產(chǎn)生什么對象實(shí)例,它只是一個(gè)靜態(tài)地址的符號(hào)名稱。
基于對象的實(shí)現(xiàn)方式
復(fù)制代碼 代碼如下:
function create(name,id)
local data={name = name,id=id};
local obj={};
function obj.GetName()
return data.name;
end
function obj.GetID()
return data.id;
end
function obj.SetName(name)
data.name=name;
end
function obj.SetID(id)
data.id=id
end
return obj;
end
o1 = create("Sam", 001)
o2 = create("Bob", 007)
o1.SetID(100)
print("o1's id:", o1.GetID(), "o2's id:",o2.GetID())
o2.SetName("Lucy")
print("o1's name:", o1.GetName(),"o2's name:", o2.GetName())
--o1's id: 100 o2's id: 7
--o1's name: Sam o2's name: Lucy
實(shí)現(xiàn)方式:把需要隱藏的成員放在一張表里,把該表作為成員函數(shù)的upvalue。
局限性:基于對象的實(shí)現(xiàn)不涉及繼承及多態(tài)。但另一方面,腳本編程是否需要繼承和多態(tài)要視情況而定。
元表
復(fù)制代碼 代碼如下:
t = {}
m = { a = " and ", b = "Li Lei", c = "Han Meimei" }
setmetatable(t, { __index = m}) --表{ __index=m }作為表t的元表
for k, v in pairs(t) do --窮舉表t
print(v)
end
print("-------------")
print(t.b, t.a, t.c)
--輸出結(jié)果
---------------
--Li Lei and Han Meimei
function add(t1, t2)
--‘#'運(yùn)算符取表長度
assert(#t1 == #t2)
local length = #t1
for i = 1, length do
t1[i] = t1[i] + t2[i]
end
return t1
end
--setmetatable返回被設(shè)置的表
t1 = setmetatable({ 1, 2, 3}, { __add = add })
t2 = setmetatable({ 10, 20, 30 }, {__add = add })
t1 = t1 + t2
for i = 1, #t1 do
print(t1[i])
end
--11
--22
--33
定義:元表本身只是一個(gè)普通的表,通過特定的方法(比如setmetatable)設(shè)置到某個(gè)對象上,進(jìn)而影響這個(gè)對象的行為;一個(gè)對象有哪些行為受到元表影響以及這些行為按照何種方式受到影響是受Lua語言約束的。比如在前面的代碼里,兩個(gè)表對象的加法運(yùn)算,如果沒有元表的干預(yù),就是一種錯(cuò)誤;但是Lua規(guī)定了元表可以“重載”對象的加法運(yùn)算符,因此若把定義了加法運(yùn)算的元表設(shè)置到那兩個(gè)表上,它們就可以做加法了。元表是Lua最關(guān)鍵的概念之一,內(nèi)容也很豐富,請參考Lua文檔了解詳情。
元表與C++虛表的比較:如果把表比作對象,元表就是可以改變對象行為的“元”對象。在某種程度上,元表可以與C++的虛表做一類比。但二者還是迥然不同的:元表可以動(dòng)態(tài)的改變,C++虛表是靜態(tài)不變的;元表可以影響表(以及其他類型的對象)的很多方面的行為,虛表主要是為了定位對象的虛方法(最多再帶上一點(diǎn)點(diǎn)RTTI)。
您可能感興趣的文章:- Lua學(xué)習(xí)筆記之表和函數(shù)
- Lua基礎(chǔ)教程之賦值語句、表達(dá)式、流程控制、函數(shù)學(xué)習(xí)筆記
- Lua中的閉包小結(jié)
- Lua中的閉包學(xué)習(xí)筆記
- LUA中的閉包(closure)淺析
- Lua學(xué)習(xí)筆記之函數(shù)、變長參數(shù)、closure(閉包)、select等
- lua閉包的理解以及表與函數(shù)的幾種表達(dá)方法