使用lua進(jìn)行腳本編程有很多優(yōu)點(diǎn): 1 代碼體積小 2 執(zhí)行速度快 3 安全性較高等 4 但是最大的優(yōu)點(diǎn)是修改后的代碼不需要重新編譯即可生效,而高級語言的代碼經(jīng)過修改后需要經(jīng)過重新編譯或者解釋后才能生效。
lua主要用于游戲應(yīng)用層的開發(fā)。由于游戲上層的邏輯會而經(jīng)常發(fā)生變化,比如游戲的任務(wù)系統(tǒng)或者活動系統(tǒng)。 我們可以設(shè)想一下,如果每次都要修改我們所用的C#代碼重新編譯,那么玩家根本就無法進(jìn)行游戲。
lua和python則是兩個常用的腳本語言,lua相對于python而言,lua比較輕量級罷了
1. 腳本在手游中是類于“大腦”的功能,所有游戲相關(guān)的邏輯代碼一般都放在腳本中,而客戶端(前臺)的代碼都則屬于“肢體”,也可以說是“播放器”, 作用只是用戶展示出UI界面的功能;那么腳本的作用那么不僅僅如此,比如地圖數(shù)據(jù)等都可以利用腳本使用; 2. 腳本在手機(jī)網(wǎng)游中的作用尤為重要,比如一款網(wǎng)游“Himi”沒有使用腳本,如果“Himi”1.0版本在發(fā)布后突然發(fā)現(xiàn)客戶端出現(xiàn)一些棘手的bug需要修復(fù), 那么你想修改那么也要等待再次更新客戶端重新提交發(fā)布才可以解決,這樣會流失一大批用戶,而且游戲每次更新也會流失掉部分用戶,這是肯定的; 但是如果“Himi”這款網(wǎng)游使用腳本的話,那么解決此類問題很eazy,比如我在“Himi”游戲中的邏輯代碼都放在腳本a.lua 中,那么如果a.lua邏輯中哪里出現(xiàn)了問題, 我們直接可以將修復(fù)后的a.lua腳本更新至服務(wù)器中,因?yàn)橐话隳_本都會定義version號,比如a.lua有bug的version:1.0,那么我們修復(fù)后的a.lua version改成1.1, 當(dāng)用戶每次啟動游戲的時候,客戶端都會將腳本的version與服務(wù)器腳本version做對比,當(dāng)server端腳本version號比當(dāng)前腳本新,那么自動下載并覆蓋當(dāng)前腳本,OK,問題解決; 不僅僅如此,比如游戲中做個活動呀,換個圖片呀等等都可以即使更新,而不是每次修改前端代碼都要重新發(fā)布新的游戲版本,造成一些損失!
lua代碼都是運(yùn)行時才編譯的,不運(yùn)行的時候就如同一張圖片、一段音頻一樣,都是文件;所以更新邏輯只需要更新腳本,不需要再編譯,因而Lua能輕松實(shí)現(xiàn)“熱更新”。 Ulua是一款非常實(shí)用的unity插件,它能讓unity支持Lua語言,而且運(yùn)行效率還不錯。
在Lua中,一切都是變量,除了關(guān)鍵字。 lua基礎(chǔ)知識 1、and or not 邏輯運(yùn)算符 邏輯運(yùn)算符認(rèn)為false 和nil 是假(false),其他為真,0 也是true. Lua中的and和or都使用“短路原則”。 a and b -- 如果a 為false,則返回a,否則返回b a or b -- 如果a 為true,則返回a,否則返回b 例如: print(4 and 5) --> 5 print(nil and 13) --> nil print(false and 13) --> false print(4 or 5) --> 4 print(false or 5) --> 5 --一個很實(shí)用的技巧:如果x 為false 或者nil 則給x 賦初始值v x = x or v 等價(jià)于 if not x then --not作用:判斷某個值是否為true,【if not x : 如果x不為true】 x = v end and的優(yōu)先級比or高。 --C 語言中的三元運(yùn)算符 --a ? b : c --在Lua中可以這樣實(shí)現(xiàn): (a and b) or c --但是這里其實(shí)有個問題,就是當(dāng)b是false或者nil時無論a是什么,最后結(jié)果都會返回c的值,用這個(a and or {c})[1] --not 的結(jié)果只返回false 或者true print(not nil) --> true --not為否定,nil為否定,兩兩否定為肯定(true) print(not false) --> true --not為否定,false為否定,兩兩否定為肯定(true) print(not 0) --> false --not為否定,0為肯定,一肯一否為否定 print(not not nil) --> false --三個否定為否定 2、注釋 單行注釋中,連續(xù)兩個減號"--"表示注釋的開始 多行注釋中,由"--[["表示注釋開始,并且一直延續(xù)到"]]"為止。 3、條件語句 另外、不要在for的循環(huán)體內(nèi)修改變量i的值,否則會導(dǎo)致不可預(yù)知的結(jié)果。 for的另一種用法,是用來遍歷迭代器 function abc( arg ) local i = 0 local function cde( ) i = i + 1 return i,arg[i] end return cde end for k,v in abc{'a','b','c'} do if v==nil then break end print('key = '..k..',value='..v) end --key=1,value=a --key=2,value=b --key=3,value=c foreach for k, v in ipairs(a) do --ipairs是Lua自帶的系統(tǒng)函數(shù),返回遍歷數(shù)組的迭代器。k表示是數(shù)組a的key,v表示的是數(shù)組a的value,不能有第三個變量 print(v) end for k in pairs(t) do --打印table t中的所有key。 print(k) end 見如下示例代碼: days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" } revDays = {} for k, v in ipairs(days) do revDays[k] = v end for k in pairs(revDays) do print(k .. " = " .. revDays[k]) end ----輸出結(jié)果為: --1 = Sunday = 7 --2 = Monday = 3 --3 = Tuesday = 4 --4 = Wednesday = 6 --5 = Thursday = 1 --6 = Friday= 5 --7 = Saturday= 2 4、語句塊 語句塊在C中是用"{"和"}"括起來的,在Lua中,它是用do 和 end 括起來的。比如: 5、賦值語句 Lua中的賦值語句和其它編程語言基本相同,唯一的差別是Lua支持“多重賦值”,如:a, b = 10, 2 * x,其等價(jià)于a = 10; b = 2 * x。 然而需要說明的是,Lua在賦值之前需要先計(jì)算等號右邊的表達(dá)式,在每一個表達(dá)式都得到結(jié)果之后再進(jìn)行賦值。 因此,我們可以這樣寫變量交互:x,y = y,x。如果等號右側(cè)的表達(dá)式數(shù)量少于左側(cè)變量的數(shù)量,Lua會將左側(cè)多出的變量的值置為nil,如果相反,Lua將忽略右側(cè)多出的表達(dá)式。 6、數(shù)值運(yùn)算 和C語言一樣,支持 +, -, *, /。但Lua還多了一個"^"。這表示指數(shù)乘方運(yùn)算。比如2^3 結(jié)果為8, 2^4結(jié)果為16。 7、比較運(yùn)算 所有這些操作符總是返回true或false。 對于字符串的比較,Lua是按照字符次序比較的。 a="123"; print(a=b); --false print(c==b); --true 對于Table,F(xiàn)unction和Userdata類型的數(shù)據(jù),只有 == 和 ~=可以用。相等表示兩個變量引用的是同一個數(shù)據(jù)。比如: a={1,2} b=a print(a==b, a~=b) --輸出 true, false a={1,2} b={1,2} print(a==b, a~=b) --輸出 false, true 8、變量類型 > print(type("hello world")) string > print(type(10.4)) number > print(type(print)) function > print(type(true)) boolean > print(type(nil)) nil > print(type(type(X))) string > print(type({1,2,3})) table 9、 變量的定義 在Lua中還有一個特殊的規(guī)則,即以下劃線(_)開頭,后面緊隨多個大寫字母(_VERSION),這些變量一般被Lua保留并用于特殊用途,因此我們在聲明變量時需要盡量避免這樣的聲明方式,以免給后期的維護(hù)帶來不必要的麻煩。 在Lua中,不管在什么地方使用變量,都不需要聲明,并且所有的這些變量總是全局變量,除非我們在前面加上"local"。這一點(diǎn)要特別注意,因?yàn)槲覀兛赡芟朐诤瘮?shù)里使用局部變量,卻忘了用local來說明。 和其它編程語言一樣,如果有可能盡量使用局部變量,以免造成全局環(huán)境的變量名污染。同時由于局部變量的有效期更短,這樣垃圾收集器可以及時對其進(jìn)行清理,從而得到更多的可用內(nèi)存。 不同lua文件之間的require的情況:如果a文件require了b文件,那么b文件里的全局變量在a文件里是能訪問到的,而局部變量是訪問不到的! function fun1 local a=10; end function fun2 print("a's value is "..a) -- 報(bào)錯:attempt to concatenate global 'a' (a nil value) end (1)Nil 正如前面所說的,沒有使用過的變量的值,都是Nil。有時候我們也需要將一個變量清除,這時候,我們可以直接給變量賦以nil值。 將nil賦予一個全局變量等同于刪除它。如: var1=nil -- 請注意 nil 一定要小寫 另外還可以像全局變量一樣,將nil賦予table的某個元素(key)來刪除該元素。 (2)Boolean 布爾值通常是用在進(jìn)行條件判斷的時候。布爾值有兩種:true 和 false。在Lua中,只有false和nil才被計(jì)算為false,而所有任何其它類型的值,都是true。比如0,空串等等,都是true。 0在Lua中的的確確是true。你也可以直接給一個變量賦以Boolean類型的值,如: theBoolean = true (3)Number Lua中的number用于表示實(shí)數(shù)。Lua中沒有專門的類型表示整數(shù)。 (4)String 字符串,總是一種非常常用的高級類型。在Lua中,我們可以非常方便的定義很長很長的字符串。 值得注意的是,在這種字符串中,如果含有單獨(dú)使用的"[["或"]]"就仍然得用"\["或"\]"來避免歧義。當(dāng)然,這種情況是極少會發(fā)生的。 在Lua中還可以通過[[ all strings ]]的方式來禁用[[ ]]中轉(zhuǎn)義字符,如: page = [[abc\n123]] --abc\n123 如果兩個方括號中包含這樣的內(nèi)容:a = b[c[i]],這樣將會導(dǎo)致Lua的誤解析,[[a = b[c[i]]]],lua會認(rèn)為倒數(shù)第二個]]為結(jié)束標(biāo)志,因此在這種情況下,我們可以將其改為[===[ 和 ]===]的形式,從而避免了誤解析的發(fā)生。 (5)Table A、 如果鍵是int類型的,那么鍵只能為這種格式的:[1]或者['1'] B、 如果鍵是string類型的,那么鍵只能為這種格式的:['name']或者name 關(guān)系表類型,這是一個很強(qiáng)大的類型。我們可以把這個類型看作是一個數(shù)組。只是C#語言的數(shù)組,只能用正整數(shù)來作索引;在Lua中,你可以用任意類型來作數(shù)組的索引,除了nil。 同樣,在C#語言中,數(shù)組的內(nèi)容只允許一種類型;在Lua中,你也可以用任意類型的值來作數(shù)組的內(nèi)容,除了nil。 T1 = {} -- 定義一個空表 T1[1]=10 --然后我們就可以象C#語言一樣來使用它了。 T1["John"]={Age=27, Gender="Male"} --這一句相當(dāng)于: T1["John"]={} -- 必須先定義成一個表,還記得未定義的變量是nil類型嗎 T1["John"]["Age"]=27 T1["John"]["Gender"]="Male" --當(dāng)表的索引是字符串的時候,我們可以簡寫成: T1.John={} T1.John.Age=27 T1.John.Gender="Male" --或 T1.John = {Age=27, Gender="Male"} 在定義表的時候,我們可以把所有的數(shù)據(jù)內(nèi)容一起寫在"{"和"}"之間,這樣子是非常方便,而且很好看。比如,前面的T1的定義,我們可以這么寫: T1= { 10, -- 相當(dāng)于 [1] = 10 ,如果不寫索引,則索引就會被認(rèn)為是數(shù)字,并按順序自動從1往后編 [100] = 40, --相當(dāng)于指定索引為100對應(yīng)的值為40 John= -- 如果你原意,你還可以寫成:["John"] = { Age=27, -- 如果你原意,你還可以寫成:["Age"] =27 Gender=Male -- 如果你原意,你還可以寫成:["Gender"] =Male }, 20 -- 相當(dāng)于 [2] = 20 } 看起來很漂亮,不是嗎?我們在寫的時候,需要注意三點(diǎn): 第一,所有元素之間,總是用逗號","隔開; 表類型的構(gòu)造是如此的方便,以致于常常被人用來代替配置文件。是的,不用懷疑,它比ini文件要漂亮,并且強(qiáng)大的多。 對于table的構(gòu)造器,還有兩個需要了解的語法規(guī)則,如: table可視為數(shù)組,數(shù)組下標(biāo)不同于其他大多數(shù)語言,其下標(biāo)從 (6)Function 函數(shù),在Lua中,函數(shù)的定義也很簡單。典型的定義如下: function add(a,b) -- add 是函數(shù)名字,a和b是參數(shù)名字 return a+b -- return 用來返回函數(shù)的運(yùn)行結(jié)果 end 還記得前面說過,函數(shù)也是變量類型嗎?上面的函數(shù)定義,其實(shí)相當(dāng)于: add = function (a,b) return a+b end 當(dāng)重新給add賦值時,它就不再表示這個函數(shù)了。我們甚至可以賦給add任意數(shù)據(jù),包括nil (這樣,賦值為nil,將會把該變量清除)。 Lua的函數(shù)可以接受可變參數(shù)個數(shù),它同樣是用"..."來定義的,比如: function sum (a,b,...) 如果想取得...所代表的參數(shù),可以在函數(shù)中訪問arg局部變量(表類型)得到 (lua5.1: 取消arg,并直接用"..."來代表可變參數(shù)了,本質(zhì)還是arg)。 function test(arg1,arg2,...) ... end 關(guān)于Lua的變長參數(shù)最后需要說明的是,由于變長參數(shù)中可能包含nil值,因此在使用類似獲取table元素?cái)?shù)量(#)的方式獲取變參的數(shù)量就會出現(xiàn)問題。如果要想始終獲得正確的參數(shù)數(shù)量,可以使用Lua提供的select函數(shù),如: function Start() MyTest(2,4,6,a,b); end function MyTest(...) print(select('#',...)) -- 5 , 這里'#'值表示讓select返回變參的數(shù)量(其中包括nil)。 for i = 1, select('#',...) do local arg = select(i, ...) --這里的i表示獲取第i個變參,1為第一個。 print(arg); end end --輸出結(jié)果 --5 = --2 --4 --6 --nil --nil 更可貴的是,它可以同時返回多個結(jié)果,比如: function s() return 1,2,3,4 end a,b,c,d = s() -- 此時,a = 1, b = 2, c = 3, d = 4 function maximum(a) local mi = 1 local m = a[mi] for i, val in ipairs(a) do if val > m then mi,m = i,val end end return m,mi end print(maximum{8,10,23,12,5}) function abcwyq( ... ) -- body return 11,22,33 end print(abcwyq()) --輸出結(jié)果為 --11 --11 22 --11 22 33 前面說過,表類型可以擁有任意類型的值,包括函數(shù)!因此,有一個很強(qiáng)大的特性是,擁有函數(shù)的表,哦,我想更恰當(dāng)?shù)膽?yīng)該說是對象吧。Lua可以使用面向?qū)ο缶幊塘?。不信?舉例如下: t = { Age = 27, add = function(self, n) self.Age = self.Age+n end } print(t.Age) -- 27 t.add(t, 10) print(t.Age) -- 37 不過,t.add(t,10) 這一句實(shí)在是有點(diǎn)土對吧?沒關(guān)系,在Lua中,我們可以簡寫成: t:add(10) -- 相當(dāng)于 t.add(t,10) 1、在Lua中函數(shù)的調(diào)用方式和C語言基本相同,如:print("Hello World")和a = add(x, y)。唯一的差別是,如果函數(shù)只有一個參數(shù),并且該參數(shù)的類型為字符串常量或table的構(gòu)造器,那么圓括號可以省略,如print "Hello World"和f {x = 20, y = 20}。 2、Lua為面對對象式的調(diào)用也提供了一種特殊的語法--冒號操作符。表達(dá)式o.foo(o,x)的另一種寫法是o:foo(x)。冒號操作符使調(diào)用o.foo時將o隱含的作為函數(shù)的第一個參數(shù)。 3、需要說明的是,Lua中實(shí)參和形參的數(shù)量可以不一致,一旦出現(xiàn)這種情況,Lua的處理規(guī)則等同于多重賦值,即實(shí)參多于形參,多出的部分被忽略,如果相反,沒有被初始化的形參的缺省值為nil。 4、 Lua會調(diào)整一個函數(shù)的返回值數(shù)量以適應(yīng)不同的調(diào)用情況。若將函數(shù)調(diào)用作為一條單獨(dú)語句時,Lua會丟棄函數(shù)的所有返回值。若將函數(shù)作為表達(dá)式的一部分來調(diào)用時,Lua只保留函數(shù)的第一個返回值。 只有當(dāng)一個函數(shù)調(diào)用是一系列表達(dá)式中的最后一個元素時,才能獲得所有返回值。這里先給出三個樣例函數(shù),如: function foo0() end function foo1() return "a" end function foo2() return "a","b" end 最后一個需要介紹的是Lua中unpack函數(shù),該函數(shù)將接收數(shù)組作為參數(shù),并從下標(biāo)1開始返回該數(shù)組(之所以不稱之為table,因?yàn)檎f成數(shù)組,更好理解,數(shù)組的特性就是從1開始,并以1為增量排序的集合)的所有元素。如: > lua > print(unpack{10,20,30}) 10 20 30 > a,b = unpack{10,20,30} > print(a,b) 10 20 > string.find(unpack{"hello","ll"}) --等同于string.find("hello","ll"),find函數(shù)的作用是尋找第二個參數(shù)ll在第一個參數(shù)中的索引位置 在Lua中unpack函數(shù)是用C語言實(shí)現(xiàn)的。為了便于理解,下面給出在Lua中通過遞歸實(shí)現(xiàn)一樣的效果,如: function unpack(t,i) i = i or 1 if t[i] then return t[i], unpack(t,i + 1) end end 具名實(shí)參: 在函數(shù)調(diào)用時,Lua的傳參規(guī)則和C語言相同,并不真正支持具名實(shí)參。但是我們可以通過table來模擬,比如: function rename1(old,new) ... end 這里我們可以讓上面的rename函數(shù)只接收一個參數(shù),即table類型的參數(shù),與此同時,該table對象將含有old和new兩個key。如: function rename2(arg) local old = arg.old local new = arg.new ... end 這種修改方式有些類似于JavaBean,即將多個參數(shù)合并為一個JavaBean。 在Lua中函數(shù)和所有其它值一樣都是匿名的,即它們都沒有名稱。在使用時都是操作持有該函數(shù)的變量,如: a = { p = print } 我們將這種函數(shù)構(gòu)造式的結(jié)果稱為一個"匿名函數(shù)"。下面的示例顯示了匿名函數(shù)的方便性,它的使用方式有些類似于Java中的匿名類,如: test_table={{age=5},{age=11},{age=1},{age=3},{age=9}} table.sort(test_table,function(a,b) return (a.age > b.age) end) for i=1,5 do print(test_table[i].age) end end --輸出結(jié)果 --11 --9 --5 --3 --1 1. closure(閉合函數(shù)): function newCounter() local i = 0 return function() --匿名函數(shù) i = i + 1 return i end end c1 = newCounter() print("The return value of first call is " .. c1()) print("The return value of second call is " .. c1()) --輸出結(jié)果為: --The return value of first call is 1 --The return value of second call is 2 在上面的示例中,我們將newCounter()函數(shù)稱為閉包函數(shù)。其函數(shù)體內(nèi)的局部變量i被稱為"非局部變量",和普通局部變量不同的是該變量被newCounter函數(shù)體內(nèi)的匿名函數(shù)訪問并操作。 再有就是在函數(shù)newCounter返回后,其值仍然被保留并可用于下一次計(jì)算。再看一下下面的調(diào)用方式。 function newCounter() local i = 0 return function() --匿名函數(shù) i = i + 1 return i end end c1 = newCounter() c2 = newCounter() print("The return value of first call with c1 is " .. c1()) print("The return value of first call with c2 is " .. c2()) print("The return value of second call with c1 is " .. c1()) --輸出結(jié)果為: --The return value of first call with c1 is 1 --The return value of first call with c2 is 1 --The return value of second call with c1 is 2 由此可以推出,Lua每次在給新的閉包變量賦值時,都會讓不同的閉包變量擁有獨(dú)立的"非局部變量"。下面的示例將給出基于閉包的更為通用性的用法: do --這里將原有的文件打開函數(shù)賦值給"私有變量"oldOpen,該變量在塊外無法訪問。 local oldOpen = io.open --新增一個匿名函數(shù),用于判斷本次文件打開操作的合法性。 local access_OK = function(filename,mode) <檢查訪問權(quán)限> end --將原有的io.open函數(shù)變量指向新的函數(shù),同時在新函數(shù)中調(diào)用老函數(shù)以完成真正的打開操作。 io.open = function(filename,mode) if access_OK(filename,mode) then return oldOpen(filename,mode) else return nil,"Access denied" end end end 非全局函數(shù): 從上一小節(jié)中可以看出,Lua中的函數(shù)不僅可以直接賦值給全局變量,同時也可以賦值給其他類型的變量,如局部變量和table中的字段等。 事實(shí)上,Lua庫中大多數(shù)table都帶有函數(shù),如io.read、math.sin等。這種寫法有些類似于C++中的結(jié)構(gòu)體。如: do local f = function(x,y) return x + y end --do something with f. f(4,5) end 對于這種局部函數(shù),Lua還提供另外一種更為簡潔的定義方式,如: 正確的尾調(diào)用: 在Lua中支持這樣一種函數(shù)調(diào)用的優(yōu)化,即“尾調(diào)用消除”。我們可以將這種函數(shù)調(diào)用方式視為goto語句,如: 由此可見,Lua解釋器一旦發(fā)現(xiàn)g()函數(shù)是f()函數(shù)的尾調(diào)用,那么在調(diào)用g()時將不會產(chǎn)生因函數(shù)調(diào)用而引起的棧開銷。這里需要強(qiáng)調(diào)的是,尾調(diào)用函數(shù)一定是其調(diào)用函數(shù)的最后一條語句,否則Lua不會進(jìn)行優(yōu)化。 然而事實(shí)上,我們在很多看似是尾調(diào)用的場景中,實(shí)際上并不是真正的尾調(diào)用,如:
(7)Userdata 和 Thread 10、字符串 (1)"#"標(biāo)識符,該標(biāo)識符在字符串變量的前面將返回其后字符串的長度 a = "hello" print(#a) --5 (2)Lua提供了運(yùn)行時的數(shù)字與字符串的自動轉(zhuǎn)換。如: > print("10" + "1") 11 > print(10 + 1) 11 > print("10 + 1") 注意..和兩邊的數(shù)字之間必須留有空格,否則就會被Lua誤解析為小數(shù)點(diǎn)兒。 盡管Lua提供了這種自動轉(zhuǎn)換的功能,為了避免一些不可預(yù)測的行為發(fā)生,特別是因?yàn)長ua版本升級而導(dǎo)致的行為不一致現(xiàn)象。 鑒于此,還是應(yīng)該盡可能使用顯示的轉(zhuǎn)換,如字符串轉(zhuǎn)數(shù)字的函數(shù)tonumber(),或者是數(shù)字轉(zhuǎn)字符串的函數(shù)tostring()。對于前者,如果函數(shù)參數(shù)不能轉(zhuǎn)換為數(shù)字,該函數(shù)返回nil。如: line = io.read() n = tonumber(line) if n == nil then error(line .. " is not a valid number") else print(n * 2) end (3)由于數(shù)組實(shí)際上仍為一個table,所以對于數(shù)組大小的計(jì)算需要留意某些特殊的場景,如: a = {} a[1000] = 1 在上面的示例中,數(shù)組a中索引值為1--999的元素的值均為nil。而Lua則將nil作為界定數(shù)據(jù)結(jié)尾的標(biāo)志。當(dāng)一個數(shù)組含有“空隙”時,即中間含有nil值,長度操作符#會認(rèn)為這些nil元素就是結(jié)尾標(biāo)志。 當(dāng)然這肯定不是我們想要的結(jié)果。因此對于這些含有“空隙”的數(shù)組,我們可以通過函數(shù)table.maxn()返回table的最大正數(shù)索引值。如: table.maxn()是返回table的最大正數(shù)索引值
一般來說#是獲得一個table的長度(即元素?cái)?shù)),但這個操作符實(shí)際上陷阱很多,#僅對鍵值為連續(xù)的數(shù)值才有效,并且鍵值必須從1開始! 如果你的table是純粹當(dāng)一個連續(xù)的數(shù)組在用,那么#t是很方便的獲得table長度的方法;但如果你的table中key的數(shù)值不連續(xù),或者有其他類型的key那么還是不要指望#能給出多有意義的結(jié)果來…… 連續(xù)的數(shù)組指的就是往一個空的table中插入數(shù)據(jù),由此table自動分配鍵值,由1開始,遞增量為1 類似這樣:t = {"a", "b", "c"},只有這種情況用#運(yùn)算符才最保險(xiǎn)!不過#運(yùn)算符主要用于計(jì)算字符串的長度 table遍歷: for key, value in pairs(tbtest) do XXX end 這樣的遍歷順序并非是tbtest中table的排列順序,而是根據(jù)tbtest中key的hash值排列的順序來遍歷的。 如果不需要保證遍歷的順序,就用pairs pairs也可以用來遍歷連續(xù)的數(shù)組(之所以不稱之為table,因?yàn)檎f成數(shù)組,更好理解,數(shù)組的特性就是從1開始,并以1為增量排序的集合),會按順序輸出 也可以遍歷不是以1開始,也不是按1遞增的連續(xù)的key的table,也會按順序輸出的,例如: a = {[4] = "red1",[3] = "red2",[5] = "red3",[1] = "red4"} for k,v in pairs(a) do print(v) -- red4 red2 red1 red3 end
for key, value in ipairs(tbtest) do XXX end 這樣的循環(huán)必須要求tbtest中的key為順序的,而且必須是從1開始,ipairs只會從1開始按連續(xù)的key順序遍歷到key不連續(xù)為止。 如果需要保證遍歷的順序,就用ipairs,前提是table是一個連續(xù)的數(shù)組
for i=1, #(tbtest) do XXX end 這種遍歷,只能遍歷連續(xù)的數(shù)組(鍵從1開始,以增量為1遞增的鍵的table),不然遍歷會出現(xiàn)意想不到的結(jié)果!
for i=1, table.maxn(tbtest) do XXX end 這種效率太低了,不建議用于遍歷table
參考:http://www.cnblogs.com/ly4cn/archive/2006/08/04/467550.html http://www.cnblogs.com/stephen-liu74/archive/2012/06/15/2409324.html |
|