Lua基礎之table詳解

概要: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和tablethis

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())
相關文章
相關標籤/搜索