概要:1.table特性;2.table的構造;3.table經常使用函數;4.table遍歷;5.table面向對象web
原文地址:http://blog.csdn.net/dingkun520wy/article/details/50231603編程
1.table特性
數組
table是一個「關聯數組」,數組的索引能夠是數字或者是字符串,全部索引值都須要用 "["和"]" 括起來;若是是字符串,還能夠去掉引號和中括號; 即若是沒有[]括起,則認爲是字符串索引閉包
table 的默認初始索引通常以 1 開始,若是不寫索引,則索引就會被認爲是數字,並按順序自動從1日後編;app
table 的變量只是一個地址引用,對 table 的操做不會產生數據影響函數
table 不會固定長度大小,有新數據插入時長度會自動增加性能
table 裏保存數據能夠是任何類型,包括function和table;this
table全部元素之間,老是用逗號 "," 隔開;lua
2.table的構造
spa
建立table
t = {} --定義一個空表 t["jun"] = 6 --字符串key值的屬性 t[1] = 1 --數字key值的屬性 t.jun = 16 --字符串key值的簡寫 t.test = {num=28,str="test"} --屬性能夠是table print(t.test.num) --輸出28 t.testFunction = function() print("函數") end --屬性能夠是function t.testFunction() --調用函數 t:testFunction() --同上 --上面的table還能夠這麼寫 t= { 1, jun = 6, test= { num = 28, str = "test", } testFunction = function() print("函數") end, }
3.table經常使用函數
table.pack(...)
獲取一個索引從 1 開始的參數表 table,並會對這個 table 預約義一個字段 n,表示該表的長度
function table_pack(param, ...) local arg = table.pack(...) print("this arg table length is", arg.n) for i = 1, arg.n do print(i, arg[i]) end end table_pack("test", "param1", "param2", "param3")
table.concat(table, sep, start, end)
table.concat()函數列出參數中指定table的數組部分從start位置到end位置的全部元素, 元素間以指定的分隔符(sep)隔開。除了table外, 其餘的參數都不是必須的, 分隔符的默認值是空字符, start的默認值是1, end的默認值是數組部分的總長.
sep, start, end這三個參數是順序讀入的, 因此雖然它們都不是必須參數, 但若是要指定靠後的參數, 必須同時指定前面的參數.
lua 中字符串的存儲方式與 C 不同,lua 中的每一個字符串都是單獨的一個拷貝,拼接兩個字符串會產生一個新的拷貝,若是拼接操做特別多,就會影響性能,因此對於密集型的字符並接,table.concat 比用 ".." 鏈接更高效。
local tbl = {"apple", "pear", "orange", "grape"} print(table.concat(tbl)) print(table.concat(tbl, "、")) print(table.concat(tbl, "、", 2)) print(table.concat(tbl, "、", 2, 3))
table.unpack(table, start, end)
用於返回 table 裏的元素,參數 start 是開始返回的元素位置,默認是 1,參數 end 是返回最後一個元素的位置,默認是 table 最後一個元素的位置,參數 start、end 都是可選
local tbl = {"apple", "pear", "orange", "grape"} print(table.unpack(tbl)) local a, b, c, d = table.unpack(tbl) print(a, b, c, d) print(table.unpack(tbl, 2)) print(table.unpack(tbl, 2, 3))
table.maxn(table)
返回指定table中全部正數key值中最大的key值. 若是不存在key值爲正數的元素, 則返回0. 此函數不限於table的數組部分.
tbl = {[1] = "a", [2] = "b", [3] = "c", [26] = "z"} print(#tbl) --3由於26和以前的數字不連續, 因此不算在數組部份內 print(table.maxn(tbl)) --26 tbl[91.32] = true print(table.maxn(tbl)) --91.32
table.getn(table)
返回table中元素的個數
t1 = {1, 2, 3, 5}; print(getn(t1)) --4
table.insert(table, pos, value)
用於向 table 的指定位置(pos)插入值爲value的一個元素. pos參數可選, 默認爲數組部分末尾.
local tbl = {"apple", "pear", "orange", "grape"} table.insert(tbl, "watermelon") print(table.concat(tbl, "、")) table.insert(tbl, 2, "watermelon") print(table.concat(tbl, "、"))
table.remove(table, pos)
刪除並返回table數組部分位於pos位置的元素. 其後的元素會被前移. pos參數可選, 默認爲table長度, 即從最後一個元素刪起,而且參數 pos 的類型只能是數字 number 類型。
local tbl = {"apple", "pear", "orange", "grape"} table.remove(tbl, 2) print(table.concat(tbl, "、")) table.remove(tbl) print(table.concat(tbl, "、"))
table.sort(table, comp)
用於對 table 裏的元素做排序操做,參數 comp 是一個排序對比函數,它有兩個參數 param一、param2,若是 param1 排在 param2 前面,那麼排序函數返回 true,不然返回 false。參數 comp 可選,缺省 comp 的狀況下是對錶做升序排序。
local tbl = {"apple", "pear", "orange", "grape"} local sort_func1 = function(a, b) return a > b end table.sort(tbl, sort_func1) print(table.concat(tbl, "、")) local sort_func2 = function(a, b) return a < b end table.sort(tbl, sort_func2) print(table.concat(tbl, "、")) local tbl = {"apple", "pear", "orange", "grape"} table.sort(tbl) print(table.concat(tbl, "、"))
table.foreachi(table, function(i, v))
會指望一個從 1(數字 1)開始的連續整數範圍,遍歷table中的key和value逐對進行function(i, v)操做
t1 = {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="hello lua"}; table.foreachi(t1, function(i, v) print (i, v) end) ; --結果1 2 --2 4 --3 6 --4 8 --5 10 --6 12
table.foreach(table, function(i, v))
與foreachi不一樣的是,foreach會對整個表進行迭代
t1 = {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="hello lua"}; table.foreach(t1, function(i, v) print (i, v) end) ; --[[ 輸出結果: 1 2 2 4 3 6 4 8 5 10 6 12 web hello lua language Lua version 5 ]]
4.table遍歷
for key, value in pairs(tbtest) do print(value) end
這樣的遍歷順序並不是是tbtest中table的排列順序,而是根據tbtest中key的hash值排列的順序來遍歷的。
for key, value in ipairs(tbtest) do
print(value)
end
這樣的循環必需要求tbtest中的key爲順序的,並且必須是從1開始,ipairs只會從1開始按連續的key順序遍歷到key不連續爲止。
5.table面向對象
和編譯型的面嚮對象語言不一樣,在lua中不存在類的定義這樣一個概念,不論是類的定義仍是類的實例都須要經過lua table來模擬。
Test = {jun = 0} function Test.withdraw(self,v) self.jun = self.jun - v end --下面是代碼的調用: a = Test a.withdraw(a,10)
Lua提供了一種更爲便利的語法,即將點(.)替換爲冒號(:),這樣能夠在定義和調用時均隱藏self參數
function Test:withdraw(v) self.jun = self.jun - v end a = Test a:withdraw(10)
類
Lua 沒有類的概念,不過能夠經過元表(metatable)來實現與原型 prototype 相似的功能,而 prototype 與類的工做機制同樣,都是定義了特定對象行爲。Lua 裏的原型特性主要使用元表的 __index 事件來實現,這樣當調用對象沒定義的方法時,會向其元表的 __index 鍵(事件)查找。例若有 a 和 b 兩個對象,想讓 b 做爲 a 的原型 prototype,只須要把 b 設置爲 a 元表的 __index 值就行:當對象 a 調用任何不存在的成員都會到對象 b 中查找,a 能夠擁有或調用 b 的屬性或方法,從某種意義上看,b 能夠看做是一個類,a 是 b 的對象。
--[[ 在這段代碼中,咱們能夠將Account視爲class的聲明,如Java中的: public class Account { public float balance = 0; public Account(Account o); public void deposite(float f); } --]] --這裏balance是一個公有的成員變量。 Account = {balance = 0} --new能夠視爲構造函數 function Account:new(o) o = o or {} --若是參數中沒有提供table,則建立一個空的。 --將新對象實例的metatable指向Account表(類),這樣就能夠將其視爲模板了。 setmetatable(o,self) --在將Account的__index字段指向本身,以便新對象在訪問Account的函數和字段時,可被直接重定向。 self.__index = self --最後返回構造後的對象實例 return o end --deposite被視爲Account類的公有成員函數 function Account:deposit(v) --這裏的self表示對象實例自己 self.balance = self.balance + v end --下面的代碼建立兩個Account的對象實例 --經過Account的new方法構造基於該類的示例對象。 a = Account:new() --[[ 這裏須要具體解釋一下,此時因爲table a中並無deposite字段,所以須要重定向到Account, 同時調用Account的deposite方法。在Account.deposite方法中,因爲self(a對象)並無balance 字段,所以在執行self.balance + v時,也須要重定向訪問Account中的balance字段,其缺省值爲0。 在獲得計算結果後,再將該結果直接賦值給a.balance。此後a對象就擁有了本身的balance字段和值。 下次再調用該方法,balance字段的值將徹底來自於a對象,而無需在重定向到Account了。 --]] a:deposit(100.00) print(a.balance) --輸出100 b = Account:new() b:deposit(200.00) print(b.balance) --輸出200
繼承
--須要說明的是,這段代碼僅提供和繼承相關的註釋,和類相關的註釋在上面的代碼中已經給出。 Account = {balance = 0} function Account:new(o) o = o or {} setmetatable(o,self) self.__index = self return o end function Account:deposit(v) self.balance = self.balance + v end function Account:withdraw(v) if v > self.balance then error("Insufficient funds") end self.balance = self.balance - v end --下面將派生出一個Account的子類,以使客戶能夠實現透支的功能。 SpecialAccount = Account:new() --此時SpecialAccount仍然爲Account的一個對象實例 --派生類SpecialAccount擴展出的方法。 --下面這些SpecialAccount中的方法代碼(getLimit/withdraw),必定要位於SpecialAccount被Account構造以後。 function SpecialAccount:getLimit() --此時的self將爲對象實例。 return self.limit or 0 end --SpecialAccount將爲Account的子類,下面的方法withdraw能夠視爲SpecialAccount --重寫的Account中的withdraw方法,以實現自定義的功能。 function SpecialAccount:withdraw(v) --此時的self將爲對象實例。 if v - self.balance >= self:getLimit() then error("Insufficient funds") end self.balance = self.balance - v end --在執行下面的new方法時,table s的元表已是SpecialAccount了,而再也不是Account。 s = SpecialAccount:new{limit = 1000.00} --在調用下面的deposit方法時,因爲table s和SpecialAccount均未提供該方法,所以訪問的仍然是 --Account的deposit方法。 s:deposit(100) --此時的withdraw方法將再也不是Account中的withdraw方法,而是SpecialAccount中的該方法。 --這是由於Lua先在SpecialAccount(即s的元表)中找到了該方法。 s:withdraw(200.00) print(s.balance) --輸出-100
私密性
私密性對於面嚮對象語言來講是不可或缺的,不然將直接破壞對象的封裝性。Lua做爲一種面向過程的腳本語言,更是沒有提供這樣的功能,然而和模擬支持類與繼承同樣,咱們仍然能夠在Lua中經過特殊的編程技巧來實現它,這裏咱們應用的是Lua中的閉包函數。
--這裏咱們須要一個閉包函數做爲類的建立工廠 function newAccount(initialBalance) --這裏的self僅僅是一個普通的局部變量,其含義徹底不一樣於前面示例中的self。 --這裏之因此使用self做爲局部變量名,也是爲了方便從此的移植。好比,之後 --若是改成上面的實現方式,這裏應用了self就能夠下降修改的工做量了。 local self = {balance = initialBalance} --這裏咱們能夠將self視爲私有成員變量 local withdraw = function(v) self.balance = self.balance - v end local deposit = function(v) self.balance = self.balance + v end local getBalance = function() return self.balance end --返回對象中包含的字段僅僅爲公有方法。事實上,咱們經過該種方式,不只能夠實現 --成員變量的私有性,也能夠實現方法的私有性,如: --local privateFunction = function() --do something end --只要咱們不在輸出對象中包含該方法的字段便可。 return {withdraw = withdraw, deposit = deposit, getBalance = getBalance} end --和前面兩個示例不一樣的是,在調用對象方法時,再也不須要self變量,所以咱們能夠直接使用點(.), --而再也不須要使用冒號(:)操做符了。 accl = newAccount(100.00) --在函數newAccount返回以後,該函數內的「非局部變量」表self就再也不能被外部訪問了,只能經過 --該函數返回的對象的方法來操做它們。 accl.withdraw(40.00) print(acc1.getBalance())