## 進階話題
## 1.函數閉包
**1.1 實例代碼**
~~~
function createCountdownTimer(second)
local ms = second * 1000 --ms為countDown的Upvalue
local function countDown()
ms = ms -1
return ms
end
return countDown
end
local timer1 = createCountdownTimer(1)
for i = 1, 3 do
print(timer1())
end
~~~
輸出結果:
**999**
**998**
**997**
**1.2 關于函數閉包描述**
- Upvalue
一個函數所使用的定義在它的函數體之外的局部變量(external local variable)稱為這個函數的upvalue。 在前面的代碼中,函數countDown使用的定義在函數createCountdownTimer 中的局部變量ms就是countDown的upvalue,但ms對createCountdownTimer而 言只是一個局部變量,不是upvalue。 Upvalue是Lua不同于C/C++的特有屬性,需要結合代碼仔細體會。
- 函數閉包
一個函數和它所使用的所有upvalue構成了一個函數閉包。?
- Lua函數閉包與C函數的比較
Lua函數閉包使函數具有保持它自己的狀態的能力,從這個意義上說,可以 與帶靜態局部變量的C函數相類比。但二者有顯著的不同:對Lua來說,函數 是一種基本數據類型——代表一種(可執行)對象,可以有自己的狀態;但 是對帶靜態局部變量的C函數來說,它并不是C的一種數據類型,更不會產生 什么對象實例,它只是一個靜態地址的符號名稱。
## 2. 基于對象的實現方式
**2.2 ?實例代碼**
~~~
local function create(name ,id )
local data = {name = name ,id = id} --data為obj.SetName,obj.GetName,obj.SetId,obj.GetId的Upvalue
local obj = {} --把需要隱藏的成員放在一張表里,把該表作為成員函數的upvalue。
function obj.SetName(name)
data.name = name
end
function obj.GetName()
return data.name
end
function obj.SetId(id)
data.id = id
end
function obj.GetId()
return data.id
end
return obj
end
~~~
輸出結果:
mycreate's id:1mycreate's name:Sam
mycreate's id:1mycreate's name:Lucy
**2.2 ?有關對象實現的描述**
**實現方式**: ?把需要隱藏的成員放在一張表里,把該表作為成員函數的upvalue。
**局限性**: ?基于對象的實現不涉及繼承及多態。但另一方面,腳本編程是否需要繼承和多態要視情況而定。?
## 3.元表
**3.1 ?實例代碼(1):**
~~~
local t = {}
local 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("有值嗎?")
print(k,"=>",v)
end
print("-------------")
print(t.b, t.a, t.c)
~~~
輸出結果:
-------------
Li LeiandHan Meimei
**3.2 ?實例代碼(2):**
~~~
local function add(t1,t2)
--‘#’運算符取表長度
assert(#t1 == #t2)
local length = #t1
for i = 1,length do
t1[i] = t1[i] + t2[i]
end
return t1
end
--setmetatable返回被設置的表
t1 = setmetatable({1,2,3},{__add = add})
t2 = setmetatable({10,20,30},{__add = add})
for k,v in pairs(t1) do
print(k,"=>",v)
end
for k,v in pairs(t2) do
print(k,"=>",v)
end
print("---------兩元表相加--------------")
t1 = t1 + t2
for i = 1 ,#t1 do
print(t1[i])
end
~~~
輸出結果:
1=>1
2=>2
3=>3
1=>10
2=>20
3=>30
---------兩元表相加--------------
11
22
33
**3.3 ?有關元表的描述:**
**定義 :**
元表本身只是一個普通的表,通過特定的方法(比如setmetatable)設置到某個對象上,進而影響這個對象的行為;一個對象有哪些行為受到元表影響以及這些行為按照何種方式受到影響是受Lua語言約束的。比如在前面的代碼里,兩個表對象的加法運算,如果沒有元表的干預,就是一種錯誤;但是Lua規定了元表可以“重載”對象的加法運算符,因此若把定義了加法運算的元表設置到那兩個表上,它們就可以做加法了。元表是Lua最關鍵的概念之一,內容也很豐富,請參考Lua文檔了解詳情。
**元表與C++虛表的比較:**
如果把表比作對象,元表就是可以改變對象行為的“元”對象。在某種程度上,元表可以與C++的虛表做一類比。但二者還是迥然不同的:元表可以動態的改變,C++虛表是靜態不變的;元表可以影響表(以及其他類型的對象)的很多方面的行為,虛表主要是為了定位對象的虛方法(最多再帶上一點點RTTI)。?
## 4. ?基于原型的繼承
4.1 實例代碼
~~~
local Robot = { name = "Sam", id = 001 }
function Robot:New(extension)
local t = setmetatable(extension or { }, self)
self.__index = self
return t
end
function Robot:SetName(name)
self.name = name
end
function Robot:GetName()
return self.name
end
function Robot:SetId(id)
self.id = id end
function Robot:GetId()
return self.id
end
robot = Robot:New()
print("robot's name:", robot:GetName())
print("robot's id:", robot:GetId())
print("-----------------")
local FootballRobot = Robot:New({position = "right back"})
function FootballRobot:SetPosition(p)
self.position = p
end
function FootballRobot:GetPosition()
return self.position
end
fr = FootballRobot:New()
print("fr's position:", fr:GetPosition())
print("fr's name:", fr:GetName())
print("fr's id:", fr:GetId())
print("-----------------")
fr:SetName("Bob")
print("fr's name:", fr:GetName())
print("robot's name:", robot:GetName())
~~~
輸出結果:
robot's name:Sam
robot's id:1
-----------------
fr's position:right back
fr's name:Sam
fr's id:1
-----------------
fr's name:Bob
robot's name:Sam
**4.2 相關描述:**
prototype模式一個對象既是一個普通的對象,同時也可以作為創建其他對象的原型的對象(即類對象,class object);動態的改變原型對象的屬性就可以動態的影響所有基于此原型的對象;另外,基于一個原型被創建出來的對象可以重載任何屬于這個原型對象的方法、屬性而不影響原型對象;同時,基于原型被創建出來的對象還可以作為原型來創建其他對象。?
## 5.包
**5.1 實例代碼:**
hello.lua
~~~
local pack = require "mypack" --導入包[注:包的名字與定義包的文件的名字相同(除去文件名后綴,在前面的代碼中,就是“mypack”)]
print(ver or "No ver defined!")
print(pack.ver)
pack.aFunInMyPack()
print(aFunInMyPack or "No aFunInMyPack defined!")
aFuncFromMyPack()
~~~
mypack.lua
~~~
module(..., package.seeall) --定義包
ver = "0.1 alpha"
function aFunInMyPack()
print("Hello!")
end
_G.aFuncFromMyPack = aFunInMyPack
~~~
輸出結果:
No ver defined!
0.1 alpha
Hello!
No aFunInMyPack defined!
Hello!
**
**
**5.2有關包的描述:**
- 定義
包是一種組織代碼的方式。
- 實現方式
一般在一個Lua文件內以module函數開始定義一個包。module同時定義了一個新的包的函數環境,以使在此包中定義的全局變量都在這個環境中,而非使用包的函數的環境中。理解這一點非常關鍵。以前面的代碼為例, “module(..., package.seeall)”的意思是定義一個包,包的名字與定義包的文件的名字相同(除去文件名后綴,在前面的代碼中,就是“mypack”),并且在包的函數環境里可以訪問使用包的函數環境(比如,包的實現使用了print,這個變量沒有在包里定義,而是定義在使用包的外部環境中)。
- 使用方式
一般用require函數來導入一個包,要導入的包必須被置于包路徑(packagepath)上。包路徑可以通過package.path或者環境變量來設定。一般來說,當前工作路徑總是在包路徑中。
- 其他
請參考Lua手冊進一步了解包的詳細說明。?
參考文獻《C/C++程序員的Lua快速入門》
- 前言
- lua學習筆記之一(C/C++程序員的Lua快速入門[初階話題])
- lua學習筆記之二(C/C++程序員的Lua快速入門[進階話題])
- lua學習筆記之三(C/C++程序員的Lua快速入門[高階話題])
- lua學習筆記之四(Lua中的基本函數庫)
- lua學習筆記之五(Lua中的數學庫)
- Lua中的table函數庫
- Lua中的常用操作系統庫
- LUA string庫
- LUA IO庫
- VS2010編譯Lua程序(lua-5.2.3)
- Lua中調用C函數(lua-5.2.3)
- Lua 常用數據結構
- lua 如何輸出樹狀結構的table?
- Lua中的元表與元方法
- lua 函數回調技巧
- Cocos2d-x使用Luajit實現加密
- Lua中的模塊與module函數
- 我所理解lua 語言中的點、冒號與self
- Lua代碼編寫規范