本文所有內(nèi)容全部都是我在閱讀了《Programming in Lua》這本書之后整理出來的,可以理解本文為一個快速查詢的“手冊”,因此并不適合零基礎的讀者。入門學習的話,還是建議先看看《Programming in Lua》這本書。本文并未包含所有的Lua語法,并不是Lua語法大全。很多高級特性,相信在你用到的時候,以下內(nèi)容肯定都已經(jīng)了然于心了,不再需要這種入門級的小手冊了。
另外,今天是愚人節(jié)!但是我并不想騙你們!以下內(nèi)容并不是愚人節(jié)的禮物,如果踩到坑,恕我無心。
關于Lua語言的一些基本常識
- Chunk 是一系列語句,Lua 執(zhí)行的每一塊語句,比如一個文件或者交互模式下的每一行都是一個 Chunk。一個 Chunk 可以是一個語句,也可以是一系列語句的組合,還可以是函數(shù),Chunk可以很大,在 Lua 中幾個 MByte 的 Chunk 是很常見的。
- 每個語句結(jié)尾的分號(;)是可選的,但如果同一行有多個語句最好用;分開
- 命令lua -la -lb首先在一個 Chunk 內(nèi)先運行 a 然后運行 b。(注意:-l 選項會調(diào)用 require,將會在指定的目錄下搜索文件,如果環(huán)境變量沒有設好,上面的命令可能不能正確運行。)
- lua -i -la -lb,-i 選項要求 Lua 運行指定 Chunk 后進入交互模式.
- dofile 函數(shù)加載文件并執(zhí)行它
- 全局變量不需要聲明,給一個變量賦值后即創(chuàng)建了這個全局變量,訪問一個沒有初始化的全局變量也不會出錯,只不過得到的結(jié)果是:nil.當且僅當一個變量不等于 nil 時,這個變量存在。
- Lua 是大小寫敏感的.
- 單行注釋:-- 注釋內(nèi)容
- 多行注釋:--[[ 注釋內(nèi)容,這里可以有多行。 --]]
- 可以直接通過命令參數(shù)傳入Lua語句。prompt> lua -e "print(math.sin(12))" --> -0.53657291800043 -e:直接將命令傳入 Lua
- 全局變量 arg 存放 Lua 的命令行參數(shù)。
類型和值
- Lua 是動態(tài)類型語言,變量不要類型定義。 Lua 中有 8 個基本類型分別為: nil、boolean、number、string、userdata、function、thread 和 table。函數(shù) type 可以測試給定變量或者值的類型。
- 關于布爾值需要注意:Lua 中所有的值都可以作為布爾值來用。在控制結(jié)構(gòu)的條件中除了 false 和 nil 為假,其他值都為真。Lua 認為 0 和空串都是真。
- 可以使用單引號或者雙引號表示字符串
- 除了雙引號和單引號,還可以使用[[...]]表示字符串。這種形式的字符串可以包含多行,可以嵌套且不會解釋轉(zhuǎn)義序列,如果第一個字符是換行符會被自動忽略掉。這種形式的字符串用來包含一段代碼是非常方便的。
- 運行時,Lua 會自動在 string 和 numbers 之間自動進行類型轉(zhuǎn)換,當一個字符串使用算術(shù)操作符時,string 就會被轉(zhuǎn)成數(shù)字。反過來,當 Lua 期望一個 string 而碰到數(shù)字時,會將數(shù)字轉(zhuǎn)成 string。
- ..在 Lua 中是字符串連接符,當在一個數(shù)字后面寫..時,必須加上空格以防止被解釋錯。print(10 .. 20) --> 1020
表達式和運算符
- Lua中不等號是~=
- 如果兩個值類型不同,Lua 認為兩者不同;nil 只和自己相等。Lua 通過引用比較 tables、userdata、functions。也就是說當且僅當兩者表示同一個對象時相等。
- Lua 比較數(shù)字按傳統(tǒng)的數(shù)字大小進行,比較字符串按字母的順序進行,但是字母順序依賴于本地環(huán)境。
- Lua的邏輯運算符是 and or not
- list 風格初始化和 record 風格初始化是[expression]一般初始化的特例
- Lua數(shù)組下標從1開始
基本語法
- Lua 可以對多個變量同時賦值,變量列表和值列表的各個元素用逗號分開,賦值語句右邊的值會依次賦給左邊的變量。a,b = 10, 2x <--> a=10; b=2x。多值賦值經(jīng)常用來交換變量,或?qū)⒑瘮?shù)調(diào)用返回給變量:a, b = f()
- 遇到賦值語句 Lua 會先計算右邊所有的值然后再執(zhí)行賦值操作,所以我們可以這樣進行交換變量的值:x, y = y, x。變量個數(shù) > 值的個數(shù) 按變量個數(shù)補足 nil,變量個數(shù) < 值的個數(shù) 多余的值會被忽略。
- 使用local 創(chuàng)建一個局部變量,與全局變量不同,局部變量只在被聲明的那個代碼塊內(nèi)有效。代碼塊:指一個控制結(jié)構(gòu)內(nèi),一個函數(shù)體,或者一個 chunk(變量被聲明的那個文件或者文本串)。
- do..end(相當于 c/c++的{})
流程控制語句
條件
if conditions then
print("hello elvin!");
end;
if conditions then
print("hello elvin!");
else
print("hello elvin!");
end;
if conditions then
print("hello elvin!");
elseif conditions then
print("hello elvin!");
-- 多個elseif
else
print("hello elvin!");
end
循環(huán)
while 語句
while condition do
print("hello elvin!");
end;
repeat-until 語句
repeat
print("hello elvin!");
until conditions;
for 語句
for 語句有兩大類
第一類,數(shù)值for循環(huán)
for var=exp1,exp2,exp3 do
loop-part
end
for 將用 exp3 作為 step 從 exp1(初始值)到 exp2(終止值),執(zhí)行 loop-part。其中exp3可以省略,默認step=1。
有幾點需要注意:
- 三個表達式只會被計算一次,并且是在循環(huán)開始前。
for i=1,f(x) do
print(i)
end
for i=10,1,-1 do
print(i)
end
第一個例子 f(x)只會在循環(huán)前被調(diào)用一次。
- 控制變量 var 是局部變量自動被聲明,并且只在循環(huán)內(nèi)有效.
for i=1,10 do
print(i)
end
max = i
-- probably wrong! 'i' here is global
如果需要保留控制變量的值,需要在循環(huán)中將其保存
-- find a value in a list
local found = nil
for i=1,a.n do
if a[i] == value then
found = i
-- save value of 'i'
break
end
end
print(found)
- 循環(huán)過程中不要改變控制變量的值,那樣做的結(jié)果是不可預知的。
如果要退出循環(huán),使用 break 語句。
第二類,范型for循環(huán)
前面已經(jīng)見過一個例子:
-- print all values of array 'a'
for i,v in ipairs(a) do
print(v)
end
范型 for 遍歷迭代子函數(shù)返回的每一個值。再看一個遍歷表 key 的例子:
-- print all keys of table 't'
for k in pairs(t) do
print(k)
end
范型 for 和數(shù)值 for 有兩點相同:
- 控制變量是局部變量
- 不要修改控制變量的值
再看一個例子,假定有一個表:
days = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"}
現(xiàn)在想把對應的名字轉(zhuǎn)換成星期幾,一個有效地解決問題的方式是構(gòu)造一個反向表:
revDays = {
["Sunday"] = 1,
["Monday"] = 2,
["Tuesday"] = 3,
["Wednesday"] = 4,
["Thursday"] = 5,
["Friday"] = 6,
["Saturday"] = 7
}
下面就可以很容易獲取問題的答案了:
x = "Tuesday"
print(revDays[x])
--> 3
其實,我們不需要手工做這件事情,可以自動構(gòu)造反向表。
revDays = {}
for i,v in ipairs(days) do
revDays[v] = i
end
Lua 語法要求break和return只能出現(xiàn)在block的結(jié)尾一句(也就是說:作為 chunk的最后一句,或者在end之前,或者else前,或者until前),有時候為了調(diào)試或者其他目的需要在block的中間使用return或者break,可以顯式的使用do..end來實現(xiàn):
do return end
函數(shù)
- 函數(shù)定義語法
function func_name(arguments-list)
statements-list;
end;
- 調(diào)用函數(shù)的時候,如果參數(shù)列表為空,必須使用()表明是函數(shù)調(diào)用。上述規(guī)則有一個例外,當函數(shù)只有一個參數(shù)并且這個參數(shù)是字符串或者表構(gòu)造的時候,()可有可無:
print "Hello World" -- -> print("Hello World")
dofile 'a.lua' -- -> dofile ('a.lua')
f{x=10, y=20} -- -> f({x=10, y=20})
type{} -- -> type({})
Lua 函數(shù)實參和形參的匹配與賦值語句類似,多余部分被忽略,缺少部分用 nil 補足。
Lua 函數(shù)可以接受可變數(shù)目的參數(shù),和 C 語言類似在函數(shù)參數(shù)列表中使用三點(...)表示函數(shù)有可變的參數(shù)。Lua 將函數(shù)的參數(shù)放在一個叫 arg 的表中,除了參數(shù)以外,arg表中還有一個域 n 表示參數(shù)的個數(shù)。
如果我們只想要 string.find 返回的第二個值。一個典型的方法是使用啞元(dummy variable,下劃線):
local _, x = string.find(s, p)
- 使用圓括號強制使調(diào)用返回一個值。
print((foo0()))
-- 將只打印foo0的第一個返回值。
- Lua中定義方法的另一種特殊方式
Lib = {}
function Lib.foo (x,y)
return x + y
end
-
當我們將函數(shù)保存在一個局部變量內(nèi)時,我們得到一個局部函數(shù),也就是說局部函數(shù)像局部變量一樣在一定范圍內(nèi)有效。
-
方式一
local f = function (...) end local g = function (...) f() -- external local `f' is visible here end
-
方式二
local function f (...) end
-
在定義非直接遞歸局部函數(shù)時要先聲明然后定義才可以
環(huán)境
Lua 用一個名為 environment 普通的表來保存所有的全局變量。
Lua 將環(huán)境本身存儲在一個全局變量_G 中,(_G._G 等于_G)。