- Lua的語法基礎(chǔ)超級簡單,非常易于上手,下面總結(jié)一些學(xué)習(xí)過程中的Lua語法基礎(chǔ):
在開始學(xué)習(xí)之前,先介紹一些最基本的概念,在Lua中具有一個代碼塊的概念,每個函數(shù)或者for循環(huán)等都是一個代碼塊。在Lua中,用
“- - ”來標(biāo)記該行的注釋,使用“- - [ [” 和 “ - - ] ] ”之間括起來的部分進(jìn)行塊注釋。如下所示:
- -- 行注釋,僅僅注釋當(dāng)前行
- for idx = 1, 10 do --在代碼之后進(jìn)行行注釋
- print("idx=",idx);
- end
- --[[
- 塊注釋,上邊的for循環(huán)結(jié)構(gòu)跟end結(jié)合起來就是一個Lua中常見的代碼塊結(jié)構(gòu)。
- --]]
另外, Lua中支持的算術(shù)運(yùn)算符有:+、-、*、/,即加、減、乘、除;支持的關(guān)系運(yùn)算符有:==、~=(不等于)、<、>、<=、>=;支持的邏輯運(yùn)算符有:and、or、not。需要注意的是,在Lua中,and邏輯運(yùn)算符如果第一個參數(shù)是false,則返回false,不會執(zhí)行第二個參數(shù)的代碼(即使第二個參數(shù)是一個錯誤的表達(dá)式,也能順利運(yùn)行);如果第一個參數(shù)是true,返回第二個參數(shù)的值。 同理,or邏輯運(yùn)算符如果第一個參數(shù)不是false,則返回第一個參數(shù)的值(不會執(zhí)行第二個參數(shù)的代碼);否則返回第二個參數(shù)的值。這就是所謂的 邏輯運(yùn)算符短路求值。
- result = true
- if result and an_donot_defined_method() then
- print("no erro occured!")
- end
- --[[
- 上述代碼輸出的錯誤如下:
- stdin:1: attempt to call global 'an_donot_defined_method' (a nil value)
- stack traceback:
- stdin:1: in main chunk
- [C]: ?
- --]]
- result =false
- if (result and an_donot_defined_method())==false then
- print("no erro occured!")
- end
- --上述代碼順利通過編譯,即使有一個沒定義的方法,打印結(jié)果:no erro occured!
一、基本數(shù)據(jù)類型
Lua中具有5種基本的數(shù)據(jù)類型,nil、Boolean、string、Number和table。在Lua中使用變量不需要提前聲明,變量的類型決定于用戶賦值的類型。可以使用 type()函數(shù)判斷變量的類型。其中,nil、Boolean、Number都是用法比較簡單的類型,string、table類型用法稍微復(fù)雜點(diǎn)。給一個變量賦值為nil,表示釋放該變量。Boolean跟其他語言一樣,只有true和false兩種值。Number是雙精度浮點(diǎn)數(shù),Lua中沒有整數(shù)類型。table類型可以當(dāng)作數(shù)組使用。
在Lua中,變量默認(rèn)是全局的,這通常導(dǎo)致一些調(diào)試?yán)щy,最好盡量顯式的在變量名之前加上 local 關(guān)鍵字聲明該變量為局部變量。
- gNumber = 10 --這是一個默認(rèn)全局的變量
- print(type(gNumber))
- --輸出結(jié)果為number
- gNumber = nil --之前的number類型gNumber = 10變量被釋放
- print(type(gNumber))
- --輸出結(jié)果為nil
-
- function LocalVarFunction ()
- local pTable = {} --用local關(guān)鍵字聲明一個局部變量,這個變量將在執(zhí)行LocalVarFunction方法后銷毀
- for idx = 1, 5 do
- local result = true --這個result將在每個for循環(huán)執(zhí)行之后銷毀
- if result then
- local pString = "這個字符串將在if代碼塊之后銷毀"
- pTable[idx] = pString
- print(pTable[idx])
- end
- end
- end
下面詳細(xì)介紹string以及table兩種類型的詳細(xì)用法。
1、string類型的用法
Lua中的字符串操作非常出色。下表是一些特殊意義的字符:
特殊的Lua字符串
| 字符 |
意義 |
字符 |
意義 |
| \a |
響鈴 |
\v |
垂直制表符 |
| \b |
退格 |
\\ |
反斜杠 |
| \f |
換頁符 |
\“ |
雙引號 |
| \n |
換行符 |
\' |
單引號 |
| \r |
換行符 |
\[ |
左方括號 |
| \t |
制表符 |
\] |
右方括號 |
a、類型轉(zhuǎn)換
Lua會根據(jù)上下文在合理合法的情況下隱式進(jìn)行數(shù)字和字符之間的轉(zhuǎn)換。另外,也可以使用tonumber()函數(shù)和tostring()函數(shù)顯式地進(jìn)行字符與數(shù)字的轉(zhuǎn)換。 見代碼實(shí)例:
- --字符與數(shù)字的隱式轉(zhuǎn)換
- print("10" + 7)
- --輸出結(jié)果為:17,將字符10隱私轉(zhuǎn)化為Number類型計(jì)算
- print("hello" + 7)
- --無法進(jìn)行運(yùn)算,即不能隱式將"hello"字符轉(zhuǎn)化為Number計(jì)算
- --[[
- 系統(tǒng)錯誤如下:
- stdin:1: attempt to perform arithmetic on a string value
- stack traceback:
- stdin:1: in main chunk
- [C]: ?
- --]]
-
-
-
- --字符與數(shù)字的顯式轉(zhuǎn)換
- print(tonumber("100")+11)
- --輸出結(jié)果為:111
- print(type(tostring(100)))
- --輸出結(jié)果為:string
b、常用的字符處理函數(shù)介紹 string.char()函數(shù)根據(jù)傳入的ASCII編碼返回該編碼對應(yīng)的字符。如:string.char(10),表示字符換行符,10是換行符的ASCII編碼。
string.len()函數(shù)求字符串的長度。如:
- print(string.len("hello"))
- --輸出結(jié)果為:5
string.sub(aString, start, end) 函數(shù)返回指定字符串的子串。如:
- gString = "hello Lua"
- print(string.sub(gString, 7,9))
- --輸出結(jié)果為:Lua
string.format()函數(shù)格式化輸出指定字符串。 %s表示字符串,%d表示所有數(shù)字,%D表示非數(shù)字,%a表示字母,%c表示控制字符,%l小寫字母,%p標(biāo)點(diǎn)符號,%s空格符號,%u大寫字母,%w字母數(shù)字,%x十六進(jìn)制數(shù),%z用0表示的字符。加%前綴可以讓特殊符號也能用在格式化中(如:().%+_*?[ ^ $ ]),如%%代表百分比符號。%.4f表示小數(shù)點(diǎn)后有4位的浮點(diǎn)數(shù),%02d.表示至少有兩個數(shù)字的整數(shù),如果不足兩個數(shù)字則用0補(bǔ)足。如:
- aString = "哈哈,你是"
- bString = "一頭豬"
- print(string.format("%s%s", aString, bString))
- --輸出結(jié)果為:哈哈,你是一頭豬
sting.find(sourceString, targetString) 函數(shù)在sourceString字符串中查找第一個符合targetString字符串的位置,如果找到則返回開始和結(jié)束的位置,沒找到則返回nil。
string.gsub(sourceString, pattern, replacementString) 函數(shù)返回一個字符串,sourceString字符中滿足pattern格式的字符都會被替換成replacementString參數(shù)的值。
string.gfind(sourceString, pattern) 函數(shù)遍歷一個字符串,一旦查找到符合指定格式的字符串就返回該子串。
一般table可以當(dāng)做數(shù)組使用,可以通過table[n]的索引形式訪問任意數(shù)組中的某個成員。在Lua中,table還能被當(dāng)做字典dictionary數(shù)據(jù)使用,并且數(shù)組跟字典的用法還能混合使用(實(shí)質(zhì)上還是數(shù)組,只不過索引從數(shù)字變成其他屬性值)。
a、使用其他值作為table的索引以及多維table
table還可以使用其他的值作為索引值,并且能用數(shù)字跟其他值同時作為同一個table的索引。如:
- gTable = {}
- gTable.name = "eric"
- gTable.gender = "man"
- gTable.phonenumber = "0000000000"
- gTable[1] = "公司"
- gTable[2] = "部門"
- for index, value in pairs(gTable) do
- print(index, value)
- end
- --[[
- 輸出結(jié)果如下:
- 1 公司
- 2 部門
- phonenumber 0000000000
- gender man
- name eric
- --]]
注意,上述循環(huán)中的pairs()函數(shù)可以遍歷table中的每一對值(索引以及索引對應(yīng)的value,有點(diǎn)類似字典,不是嗎?)
事實(shí)上,table的索引還可以是table本身,這樣就組成了一個多維table或多維字典。跟其他語言的多維數(shù)組或字典比起來,使用真是超級方便,非常非常的靈活。如:
- gTable = {}
- gTable.name = "eric"
- gTable.gender = "man"
- gTable.phonenumber = "0000000000"
- gTable[1] = "公司"
- gTable[2] = "部門"
- gTable.hobby = {"跑步", "讀書", "游戲", "動漫"} -- 多維table,可以通過gTable.hobby[1]的方式訪問.即gTable.hobby本身也是一個table
- gTable.secTable = {}
- gTable.secTable.job = "程序員"
- gTable.secTable.label = "寫代碼的"
- gTable.secTable.description = "職責(zé)是實(shí)現(xiàn)產(chǎn)品的邏輯"
-
- for index, value in pairs(gTable) do
- print(index, value)
- if ("table" == type(value)) then
- for idx, var in pairs(value) do
- print("二維table:", idx, var)
- end
- end
- end
- --[[
- 輸出結(jié)果如下:
- 1 公司
- 2 部門
- hobby table: 0x7fdceac14bc0
- 二維table: 1 跑步
- 二維table: 2 讀書
- 二維table: 3 游戲
- 二維table: 4 動漫
- phonenumber 0000000000
- gender man
- secTable table: 0x7fdceac15100
- 二維table: label 寫代碼的
- 二維table: description 職責(zé)是實(shí)現(xiàn)產(chǎn)品的邏輯
- 二維table: job 程序員
- name eric
- --]]
b、table 的常用函數(shù)
table.getn()函數(shù),返回table中元素的個數(shù)。如:
- gStringTable = {"a", "b","c","d","e"}
- for i = 1, table.getn(gStringTable) do
- print(gStringTable[i])
- end
table.sort()函數(shù),將table中的元素從小到大排列。如:
- gNumberTable = {10, 5, 7, 2,3, 2}
- table.sort(gNumberTable)
- for i = 1, table.getn(gNumberTable) do
- print(gNumberTable[i])
- end
- --輸出結(jié)果如下:
- 2
- 2
- 3
- 5
- 7
- 10
table.insert(pTable, position, value) 函數(shù)在table中插入一個新值,位置參數(shù)如果沒指定,則默認(rèn)將新值插入到table的末尾。
table.remove(pTable, position) 函數(shù)從指定table中刪除指定位置的元素并返回該元素,如果沒有指定刪除的位置,則默認(rèn)刪除table的最后一個元素。
介紹到這里, Lua中基本的數(shù)據(jù)類型諸位應(yīng)該都能掌握,休息一下,下面接著開始簡單介紹Lua的基本語句以及函數(shù)。
二、Lua中的常用語句結(jié)構(gòu)以及函數(shù)
1、Lua中的常用語句結(jié)構(gòu)介紹
- --if 語句結(jié)構(gòu),如下實(shí)例:
- gTable = {"hello", 10}
- if nil ~= gTable[1] and "hello" == gTable[1] then
- print("gTable[1] is" , gStringTable[1])
- elseif 10 == gTable[2] then
- print("gTable[2] is", gTable[2])
- else
- print("unkown gTable element")
- end
- --while 和repeat循環(huán)語句結(jié)構(gòu),while先判斷條件,如果true才執(zhí)行代碼塊(有可能跳過該代碼塊);repeat則是在最后判斷條件,保證代碼塊至少執(zhí)行一次。
- gTable = {1,2,3,4,5,6,7,8,9,10}
- index = 1
- while gTable[index] < 10 do
- print("while gTable[",index,"] is ",gTable[index])
- index = index + 1 -- 注意,Lua不支持index++或者index += 1形式的運(yùn)算符。
- end
- --[[
- while循環(huán)輸出結(jié)果如下:
- while gTable[ 1 ] is 1
- while gTable[ 2 ] is 2
- while gTable[ 3 ] is 3
- while gTable[ 4 ] is 4
- while gTable[ 5 ] is 5
- while gTable[ 6 ] is 6
- while gTable[ 7 ] is 7
- while gTable[ 8 ] is 8
- while gTable[ 9 ] is 9
- --]]
-
- --上一個循環(huán)結(jié)束后,index = 10
- repeat
- print("repeat gTable[",index,"] is ",gTable[index])
- index = index - 2
- until index < 1
- --[[
- 輸出結(jié)果如下:
- repeat gTable[ 10 ] is 10
- repeat gTable[ 8 ] is 8
- repeat gTable[ 6 ] is 6
- repeat gTable[ 4 ] is 4
- repeat gTable[ 2 ] is 2
- --]]
- --for循環(huán)結(jié)構(gòu),for循環(huán)結(jié)構(gòu)具有三個參數(shù),初始值,結(jié)束值,每個循環(huán)增加值。
- for index = 1, 5 do --不設(shè)置第三個參數(shù)的話,默認(rèn)缺省第三個參數(shù)是1,即每個循環(huán) index 增加1
- print("for cycle index =",index)
- end
- --[[
- 輸出結(jié)果為:
- for cycle index = 1
- for cycle index = 2
- for cycle index = 3
- for cycle index = 4
- for cycle index = 5
- --]]
-
- for index = 20 , 0, -5 do --設(shè)定第三個參數(shù)為-5
- print("for cycle index:",index)
- end
- --[[
- 輸出結(jié)果:
- for cycle index: 20
- for cycle index: 15
- for cycle index: 10
- for cycle index: 5
- for cycle index: 0
- --]]
- --break關(guān)鍵字可以使循環(huán)強(qiáng)制退出,Lua中沒有continue關(guān)鍵字,需要通過其他方式實(shí)現(xiàn)continue關(guān)鍵字,比如if-else語句?;蛘咄ㄟ^網(wǎng)絡(luò)下載Lua的continue關(guān)鍵字補(bǔ)丁安裝來解決該問題
-
- for index = 1, 100, 5 do
- if index > 10 and index < 25 then --用if-else語句實(shí)現(xiàn)continue關(guān)鍵字的功能
- print("continue!!!!! index=",index)
- else
- if index > 15 and index < 35 then
- print("break~~~~~index=",index)
- break
- end
- print("At end index=",index)
- end
- end
-
- --[[
- 輸出結(jié)果如下:
- At end index= 1
- At end index= 6
- continue!!!!! index= 11
- continue!!!!! index= 16
- continue!!!!! index= 21
- break~~~~~index= 26
- --]]
- --最后還要提的一點(diǎn)是,Lua中switch語句的缺失,用if-elseif-else語句代替的話,顯得非常臃腫,還有其他的一些實(shí)現(xiàn)方案。筆者在網(wǎng)上麥子加菲童鞋的博客中找到一種Lua中代替switch語句非常優(yōu)雅的方案。下面貼出麥子加菲原代碼:
- --Switch語句的替代語法(所有替代方案中覺得最好,最簡潔,最高效,最能體現(xiàn)Lua特點(diǎn)的一種方案)
- action = {
- [1] = function (x) print(x) end,
- [2] = function (x) print( 2 * x ) end,
- ["nop"] = function (x) print(math.random()) end,
- ["my name"] = function (x) print("fred") end,
- }
-
- while true do
- key = getChar()
- x = math.ramdon()
- action[key](x)
- end
2、Lua中的函數(shù)
在Lua腳本中,函數(shù)是以function關(guān)鍵字開始,然后是函數(shù)名稱,參數(shù)列表,最后以end關(guān)鍵字表示函數(shù)結(jié)束。需要注意的是,函數(shù)中的參數(shù)是局部變量,如果參數(shù)列表中存在(...)時,Lua內(nèi)部將創(chuàng)建一個類型為table的局部變量arg,用來保存所有調(diào)用時傳遞的參數(shù)以及參數(shù)的個數(shù)(arg.n)。
- function PrintTable (pTable)
- for index = 1, table.getn(pTable) do
- print("pTable[",index,"] =",pTable[index])
- end
- end
-
- gStringTable = {"hello","how","are","you"}
- PrintTable(gStringTable)
- --[[
- 輸出結(jié)果為:
- pTable[ 1 ] = hello
- pTable[ 2 ] = how
- pTable[ 3 ] = are
- pTable[ 4 ] = you
- --]]
-
- function PrintFriendInfo (name, gender, ...)
- local friendInfoString = string.format("name:%s gender:%d",name,gender)
- if 0 < arg.n then
- for index = 1, arg.n do
- friendInfoString = string.format("%s otherInfo:%s",friendInfoString, arg[index])
- end
- end
- print(friendInfoString)
- end
-
-
- PrintFriendInfo ("eric", 1, "程序員","2b", 50)
-
- --輸出結(jié)果為:
- -- name:eric gender:1 otherInfo:程序員 otherInfo:2b otherInfo:50
Lua函數(shù)的返回值跟其他語言比較的話,特殊的是能夠返回多個返回值。return之后,該Lua函數(shù)從Lua的堆棧里被清理。
- function GetUserInfo ()
- local name = "eric"
- local gender = 1
- local hobby = "動漫"
- return name, gender, hobby
- end
-
- print(GetUserInfo())
-
- --輸出結(jié)果:eric 1 動漫
三、Lua中的庫函數(shù)
在本文的最后,介紹一些Lua中常用的庫函數(shù)。
1.數(shù)學(xué)庫
math庫的常用函數(shù):三角函數(shù)math.sin、math.cos、取整函數(shù)math.floor、math.ceil、math.max、math.min、隨機(jī)函數(shù)math.random、math.randomseed(os.time())、變量pi和huge。
2、I/O庫
進(jìn)行I/O操作前,必須先用io.open()函數(shù)打開一個文件。io.open()函數(shù)存在兩個參數(shù),一個是要打開的文件名,另一個是模式字符,類似"r"表示讀取、“w”表示寫入并同時刪除文件原來內(nèi)容,“a”表示追加,“b”表示打開二進(jìn)制文件。該函數(shù)會返回一個表示文件的返回值,如果打開出錯則返回nil,寫入之前需要判斷是否出錯,比如:local file = assert(io.open(filename, “w”))..使用完畢后,調(diào)用io.close(file).或file:close()。
幾個常用I/O函數(shù):io.input ()、io.output ()、 io.read()、 io.write()。
- local file = assert(io.open(filename, “w”))
- if file ~= nil then
- file:write("hello lua!!!!") --注意,等同于io.write("hello lua!!!!")
- file:close() --等同于io.close(file)
- end
3、調(diào)試庫
debug.getinfo()函數(shù),他的第一個參數(shù) 可以是一個函數(shù)或一個棧層。返回結(jié)果是一個table,其中包含了函數(shù)的定義位置、行號、函數(shù)類型、函數(shù)名稱等信息。
debug.getlocal()函數(shù)檢查函數(shù)任意局部變量,有兩個參數(shù),第一個是希望查詢的函數(shù)棧層,另一個是變量的索引。
assert(trunk)() 函數(shù),執(zhí)行參數(shù)中代碼塊并在出錯時提供報(bào)錯功能。
- a = "hello world"
- b = "print(a)"
- assert(loadstring(b))()
- --輸出結(jié)果:
- hello world
4、幾個處理Lua代碼塊的函數(shù)
loadstring(pString)()函數(shù)可以直接執(zhí)行pString字符串組成的Lua代碼,但不提供報(bào)錯功能。
- loadstring("for index = 1, 4 do print(\"for cycle index =\",index) end")()
- --[[
- 輸出結(jié)果
- for cycle index = 1
- for cycle index = 2
- for cycle index = 3
- for cycle index = 4
- --]]
dofile(filename)函數(shù)的功能是載入并立刻執(zhí)行Lua腳本文件??梢杂脕?/span>載入定義函數(shù)的文件或者數(shù)據(jù)文件、或立即執(zhí)行的Lua代碼。dofile函數(shù)會將程序的執(zhí)行目錄作為當(dāng)前目錄。如果要載入程序執(zhí)行目錄的子目錄里的文件,需要加上子目錄的路徑。
- dofile("/Users/ericli/WorkSpace/Lua語言/hellolua.lua")
- --輸出結(jié)果:Hello Lua!
本篇總結(jié)完畢,本篇只是總結(jié)了 Lua的一些最基本的語法。至于 Lua的更高級的內(nèi)容,比如:協(xié)同程序、模塊與包、 Lua調(diào)用 C代碼、 C++與Lua的整合等,還需要在以后的學(xué)習(xí)過程中深入。
參考資料:
解決Lua語法缺失及替代措施
書籍:《Lua程序設(shè)計(jì)》、《Lua游戲開發(fā)實(shí)踐指南》
|