- Cocos2d-x游戲開發(fā):手把手教你Lua語言的編程方法
- 劉克男
- 3841字
- 2020-05-21 18:02:38
2.2.2 Lua語法
最新的Lua版本是5.3版本,但使用最廣泛的Lua版本是5.1版本。
Lua 5.1與5.3的設(shè)計理念不一樣,語法上也有所不同,Cocos2d-Lua集成的Lua解析器是5.1版本。本書涉及的Lua均指Lua 5.1。
1.命名規(guī)范
Lua中命名規(guī)范基本上與C語言一樣。
Lua中的標(biāo)識符可以由任意字母組合、數(shù)字和下畫線構(gòu)成,但不能以數(shù)字開頭,并且應(yīng)該避免以下畫線開頭,或后面是幾個大寫字母的命名方式。下面是幾個正確的命名方式:

不要使用Lua中的關(guān)鍵字。Lua中的關(guān)鍵字很少,只有21個,為變量命名時,不能使用相同的名稱。關(guān)鍵字如下:and、break、do、else、elseif、end、false、for、function、if、in、local、nil、not、or、repeat、return、then、true、until、while。
Lua區(qū)分大小寫。
2.類型與值
Lua是一種動態(tài)類型語言。在語言中沒有定義類型的語法,每個值本身就包含了類型信息。對于一個變量來說,它的值的類型是可以隨意改變的。
Lua有8種基礎(chǔ)類型:
(1)nil——空。
(2)boolean——布爾。
(3)number———數(shù)字
(4)string———字符串。
(5)function———函數(shù)。
(6)table———表。
(7)userdata———自定義數(shù)據(jù)類型。
(8)thread———線程。
函數(shù)type用來檢測一個變量的類型。

下面重點介紹其中的5種基礎(chǔ)類型。
1)nil
在Lua中nil表示的是一種類型,它只包含一個值nil。任何變量在未賦值之前都是nil。當(dāng)給一個全局變量賦值nil時,表示刪除這個變量。
2)boolean
boolean有兩個值:true和false。在Lua中,只有false和nil表示假,其他情況都為真,數(shù)字0也為真。例如下面的代碼:

① 當(dāng)不給var賦值時,輸出為var is false。
② 當(dāng)local var=false時,輸出為var is false。
③ 當(dāng)local var=true時,輸出為var is true。
④ 當(dāng)local var=0時,輸出為var is true(區(qū)別于C/C++語言)。
⑤ 當(dāng)local var=""時,輸出為var is true。
3)number
在Lua中,number類型表示實數(shù)。不論浮點數(shù)還是整型數(shù)都是number類型。有人可能會擔(dān)心number浮點數(shù)的效率,其實現(xiàn)在的CPU大部分都有單獨的協(xié)處理器計算浮點數(shù),因此浮點數(shù)的運算效率完全不是問題。
Lua中的number既可以使用普通寫法,也可以使用科學(xué)計數(shù)法。例如,下面都是正確的:

4)string
Lua中的字符串表示的是一個字符序列。里面可以包含任意字符,包括數(shù)字0(C/C++中的字符串終止字符)。并且Lua中字符串的長度是不作限制的,既可以是空字符串,也可以是整本書,Lua對字符串的處理是很快的。一般定義一個字符串變量如下:

在Lua中,單引號和雙引號都可以作為字符串的標(biāo)識,建議統(tǒng)一使用一種。如果字符串有多種格式,則可以使用下面的方式定義字符串:

當(dāng)字符串中有多個連在一起的方括號時,可以在兩個方括號之間添加多個“=”。例如:

當(dāng)需要連接兩個字符串時,可以使用字符串連接操作符“..”(類似于C語言中的strcat)。例如:

當(dāng)需要獲取字符串的長度時,可以使用“#”獲取字符串的總長度。例如:
5)table

Lua中的table類似于C++中的map,但是相對于map的煩瑣,table極大簡化了使用過程中的操作。例如,要在C++中聲明一個string,string
的map,定義如下:

而在Lua中只需要這樣聲明:

3.表達式
1)算術(shù)運算符
算術(shù)運算符有+(加)、-(減)、?(乘)、/(除)、^(指數(shù))、%(取模)、-(負號)。

注:Lua中的除法不區(qū)分整型和浮點,這里計算的結(jié)果是浮點數(shù)。
2)關(guān)系運算符
關(guān)系運算符有<(小于)、>(大于)、<=(小于等于)、>=(大于等于)、~=(不等于)、==(等于)。
對于table、userdata和function類型,Lua中是以它們的引用做比較的。即只有在它們指向同一個對象時才是相等的。
3)邏輯操作符
邏輯操作符有and(與)、or(或)和not(非)。
(1)對于and,當(dāng)?shù)谝粋€操作數(shù)為假時,返回第一個操作數(shù),否則返回第二個操作數(shù)。
(2)對于or,當(dāng)?shù)谝粋€操作數(shù)為真時,返回第一個操作數(shù),否則返回第二個操作數(shù)。
這樣使用會帶來一些語法上的便利。例如,有時會需要判斷一個值是否為空,如果為空,則給它賦值,正常的寫法是。

而Lua中則可以簡化如下:

4)字符串連接操作符
字符串連接操作符“..”用來連接兩個字符串,當(dāng)后一個為其他類型時會轉(zhuǎn)為字符串。例如:

數(shù)字2先轉(zhuǎn)化為字符串再與"Hello"做字符串拼接。
5)操作符優(yōu)先級
操作符優(yōu)先級如下(由高到低):

除了指數(shù)操作符“^”和連接操作符“..”是右連接外,其他操作符是左結(jié)合。
6)table構(gòu)造式
構(gòu)造式用來創(chuàng)建和初始化table的表達式,是Lua中特有的一種表達式。最簡單的構(gòu)造式如下:

構(gòu)造式還可以初始化一個字典類型的table,如下:

在構(gòu)造一個Lua table時,如果不給它一個key,那么其他默認的key就是從1開始的。例如,要聲明一個有關(guān)星期的table:

這樣一個table,它的構(gòu)造應(yīng)該是這樣的:

這段代碼看起來是不是很眼熟呢?它其實就是以前使用過的數(shù)組。如果想在一個table中既使用數(shù)組又使用map,也可以像下面這樣構(gòu)造一個table:

如果比較習(xí)慣C/C++語言中結(jié)構(gòu)體的用法,也可以這樣給一個table賦值:

還可以使用混合方式給table賦值,未設(shè)置key的項,key會自動從1開始編號:

刪除一個table項,只需要給它賦值為nil就行了。例如:

4.語句
1)賦值語句
Lua中的賦值,直接使用賦值操作符。例如:

當(dāng)有多個參數(shù)賦值時,可以同時給多個參數(shù)賦值。例如:

這個功能在交換值和函數(shù)需要返回多個參數(shù)時很有用。例如,在C語言中交互兩個值需要這樣做:

在Lua中不需要臨時變量做中介,只需要:

同樣地,如果函數(shù)需要返回多個值時,可以這樣寫:

2)局部變量與塊
Lua中也有局部變量和全局變量之分。定義一個局部變量,只需要在變量名稱前面加一個local關(guān)鍵字,不加local修飾的變量均是全局變量。例如:

局部變量的作用域只在聲明它的塊內(nèi)。例如,一個局部變量如果只在函數(shù)內(nèi)聲明,則退出函數(shù)時它就不能被訪問了。若一個局部變量在循環(huán)中聲明,那么循環(huán)結(jié)束時,局部變量的生命周期也結(jié)束了。
(1)如果變量沒有賦值,則會自動被賦值為nil。
(2)如果賦值操作符的左邊的變量更多,那么多出來的變量會自動被賦值為nil。
(3)如果賦值操作符的右邊的值更多,那么多余的值會被拋棄。
(4)如果需要在一段代碼塊中再插入一段代碼塊,則可以使用do…end。例如:

3)控制語句
(1)if…then…else
if語句與其他語言中的if判斷作用是一樣的,只是寫法略有不同。在C語言中寫一個if判斷如下:

在Lua中應(yīng)該這樣寫:

Lua中不支持switch語句,條件判斷只有if語句。
(2)while
while語句同其他語言中的while語句一樣。例如,C語言中這樣寫while語句:

在Lua中,應(yīng)該這樣寫:

(3)repeat … until
Lua中的repeat語句類似于C語言中的do…while語句,都是先執(zhí)行一次,然后再判斷條件是否滿足。例如,在C語言中這樣寫do…while語句:

在Lua中,應(yīng)該這樣寫:

與其他語言不同的是,repeat…until中定義的局部變量作用域范圍包括until中的語句。需要注意的是,repeat…until的停止循環(huán)的條件是true。
(4)for
Lua中的for語句分成兩種:數(shù)字for循環(huán)和泛型for循環(huán)。
①數(shù)字型for循環(huán)的語法類似于VBasic中的for語句寫法:

表示從from到to,每次遞增step。step參數(shù)默認是1。
注:for循環(huán)中的參數(shù)為表達式或者函數(shù)調(diào)用時,只會調(diào)用一次。
②泛型for循環(huán)通過一個迭代器(iterator)函數(shù)遍歷所有值,與C++中的vector之類的STL庫遍歷類似,但是使用起來更簡單方便。
Lua庫為泛型for循環(huán)提供了幾個迭代器函數(shù):io.lines用于遍歷每行;pairs用于迭代table元素;ipairs用于迭代數(shù)組元素;string.gmatch用于迭代字符串中的單詞。
泛型for循環(huán)的使用非常廣泛。例如,遍歷一個table:

注:for循環(huán)的step無法在循環(huán)體內(nèi)修改,這一點和C/C++不同。實際上,每次循環(huán)for會新生成一個局部var變量。
(5)break與return
break跳出當(dāng)前塊,return結(jié)束當(dāng)前函數(shù)。break和return只能是塊的最后一條語句,否則需要用do break end構(gòu)造一個塊。
5.函數(shù)
1)函數(shù)定義
函數(shù)是封裝和抽象塊的主要機制。函數(shù)的主要功能就是在內(nèi)部封裝一些需要的功能模塊,并且對外只開放函數(shù)名稱和參數(shù)。Lua中函數(shù)的定義與其他語言基本一樣。

不管函數(shù)是否有參數(shù),都必須有(),并且以function開頭,以end結(jié)尾。end可以不另起一行,如下:

以上兩種定義方式的效果是一樣的。
在面向?qū)ο缶幊讨薪?jīng)常會定義內(nèi)部方法,在Lua中怎么定義呢?關(guān)于面向?qū)ο缶幊淘诤竺娴恼鹿?jié)中會講到,下面看一下定義對象的方法:

首先定義了一個名為class的table,然后在table上定義了兩個函數(shù)成員,func1()和func2()使用了不同的定義方法。
這兩種定義形式從表面上看是“.”與“:”的區(qū)別。在Lua中,使用“:”定義的函數(shù)會自動傳入一個名為self的變量,self同C++中的this一樣,表示當(dāng)前對象的指針;而“.”定義的函數(shù)沒有self。
func1()和func2()可以用如下的方式等價:

2)函數(shù)參數(shù)與返回值
Lua中函數(shù)的參數(shù)可以有任意多個,當(dāng)給函數(shù)傳遞參數(shù)時超過了函數(shù)定義的形參個數(shù),那么多余的參數(shù)會被丟棄。如果傳入的參數(shù)比形參少,那么缺少的形參的值默認為nil。
Lua中如果函數(shù)返回多個參數(shù),所賦值的表達式不是最后一個元素,那么函數(shù)只返回一個值用來賦值給變量,例如:

return返回一個函數(shù)的返回值,需要注意的是,return f()語句會把f()返回的所有返回值都返回,而return(f())會迫使它只能返回一個結(jié)果。
關(guān)于多重返回值還有一個特殊的函數(shù)unpack,它接收一個數(shù)組作為參數(shù),并從下標(biāo)1開始返回該數(shù)組所有元素。

unpack常用于函數(shù)參數(shù)傳遞。

3)可變參數(shù)
Lua中的函數(shù)也可以接受數(shù)量不定的實參。例如,在print時可以傳入多個實參。下面是一個定義參數(shù)可變的函數(shù)的例子。

參數(shù)表中的3個點“…”表示該函數(shù)可以接收不同數(shù)量的實參。當(dāng)這個函數(shù)被調(diào)用時,它的所有參數(shù)都會被收集到一起。這部分收集起來的實參稱為這個函數(shù)的變長參數(shù)。訪問變長參數(shù)可以用{…}。
4)閉包函數(shù)
閉包函數(shù)是指將一個函數(shù)寫在另一個函數(shù)之內(nèi),這個位于內(nèi)部的函數(shù)可以訪問外部函數(shù)中的局部變量。下面是一個簡單例子:

在這段代碼中,匿名函數(shù)訪問了一個非局部的變量i,i用來保持一個計數(shù)器。表面上看到,由于創(chuàng)建變量i的函數(shù)(newCounter)已經(jīng)返回,所以之后每次調(diào)用匿名函數(shù)時,i均已經(jīng)超出了它的作用域;但是因為匿名函數(shù)一直在使用變量i,所以Lua會正確地維護i的生命周期。
在匿名函數(shù)內(nèi)部,i既不是全局變量,也不是局部變量,它被稱為外部的局部變量或upvalue。
閉包大量地使用在各種編程語言中,特別是它在回調(diào)函數(shù)方面的便利性,讓人們對它愛不釋手。
- OpenStack Cloud Computing Cookbook(Third Edition)
- C#程序設(shè)計實訓(xùn)指導(dǎo)書
- Learning Apex Programming
- NLTK基礎(chǔ)教程:用NLTK和Python庫構(gòu)建機器學(xué)習(xí)應(yīng)用
- Django開發(fā)從入門到實踐
- 從0到1:HTML+CSS快速上手
- Bootstrap Essentials
- Python數(shù)據(jù)可視化之Matplotlib與Pyecharts實戰(zhàn)
- C/C++程序員面試指南
- Java Web從入門到精通(第3版)
- Web App Testing Using Knockout.JS
- Deep Learning with R Cookbook
- Building Dynamics CRM 2015 Dashboards with Power BI
- 奔跑吧 Linux內(nèi)核
- 從零開始學(xué)Python大數(shù)據(jù)與量化交易