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