Lua基礎學習
要學習tolua++的使用,首先也得先學會lua的基本語法和lua與c/c++之間的接口調用。本次總結意在把lua的一些基本的用法總結歸納一下,好讓大家可以在短時間內對lua有一個簡單的瞭解,達到可以看懂lua代碼的目的。
注:
註釋:單行註釋:--
多行註釋:--[[ --]]
lua大小寫敏感
1. 基本類型
1.1 nil
它就相當於c++裏邊的NULL,但又與NULL不同,lua中的全局變量變量如果沒有賦初值,則它的值就默認等於nil,如果想要刪除一個全局變量變量,則可以給它賦值nil。
1.2 booleans
它的取值跟c++一樣,有true和false兩種。但是在lua中有一個特別的地方,在判斷語句的時候,除了false和nil爲假,其它的值都爲真,這點c++程序員應該格外注意,0和空串也爲真。
1.3 numbers
在lua中number代表實數,他強大的可以代表任何你能想象到的數字(玩笑開大啦),在應用中去探索吧。例:整數、浮點、指數似乎還有複數等。
1.4 strings
lua中的string就類似c++中的const char[],不過人家是通過lua來自動分配內存和釋放內存的。另外注意那個const,它的值是不允許修改的;
它支持轉義字符,類似c++的轉義字符;
lua會自動在string和numbers之間自動進行類型轉換,當一個字符串使用算術操作符時,string就會被轉成數字,如果string中的內容並非number的時候,可會報錯哦;
在lua中字符串的連接符是..,如果要連接的是數字,則要在..和數字間留一個空格;
另外lua還提供tonumber()和tostring()函數,支持數字和字符串間的轉換,不過在字符串轉換數字的時候,如果字符串不是正確的數字tonumber()會返回nil。
1.5 functions
在lua中,函數也可以作爲變量保存,可以作爲函數的參數和返回值,瞭解到這個,你就可以在你的lua代碼中發揮自己的想象去實現一些強大的功能啦。
1.6 userdata
顧名思義,就是用戶自己定義的類型,其實就是在lua和c++交互過程中,c++定義的 類型。
2. 表達式
2.1 算數運算符
跟c++一樣,加減乘除啥的。
2.2 關係運算符
跟c++類似,就是!=換爲~=。
2.3 邏輯運算符
這個可比較特別哦,要多加註意,lua的邏輯運算符有not、and、or;
lua中只有false和nil爲假,其它都爲真;
not a: a爲false,值爲true,a爲true,值爲false;
a and b: 如果a爲false,則取a值,否則取b值;
a or b: 如果a爲true,則取a值,否則取b值;
c++中的三目運算符a?b:c在lua中的實現:(a and b) or c。
2.4 連接運算符
.. -- 這個前邊介紹過,就是連接兩個字符串
2.5 優先級
類似c++,按老套路用就行
2.6 表的構造
這是lua的重頭戲,它的構造函數是{}。
table = {} -- 創建一個空表
表裏邊可以存放任意類型的成員,就把它當做一個c++的類即可,以下聚幾個例子
test = {“a”,”b”,”c”,”d”,”e”,”f”,”g”}
print (test[4]) -- d // 這裏注意,lua的下標操作是從1開始計算的
test = {x=1,y=2,z=3}
print (test.x,test.y,test.z) -- 1 2 3
test[1] = "a"
test1 = {"b","c"}
test1.a = test
print (test[1],test.x,test.y,test.z) -- a 1 2 3
print (test1.a[1],test1.a.x,test1[1]) -- a 1 b
更多細節請參照lua官網
3. 基本語法
3.1 賦值
lua可以對多個變量同時賦值,各變量和值用逗號分隔,賦值語句右邊的值會依次賦給左邊的變量;
當變量個數比值多時,多出的變量會賦值nil;
當變量個數少於值時,多餘的值會忽略;
例:
x,y = y,x -- 交換x和y的值
a,b,c = 0,1 -- a=0,b=1,c=nil
a,b = 3,2,1 -- a=3,b=2
3.2 局部變量
lua使用local創建局部變量,它的作用域就跟c++類似,不過它沒有{},取而代之的是do..end,如果想要設置一個局部變量,則可以將它定義在do..end當中;
lua中使用局部變量有兩個好處:
- 避免命名衝突
- 訪問局部變量的速度比全局變量快
例:
do
local a = 2
b = 4
print (a,b) -- 2 4
end
print (a,b) -- nil 4
3.3 控制語句
3.3.1 if語句
if conditions then
then-part
end;
if conditions then
then-part
else
else-part
end;
if conditions then
then-part
elseif conditions then
elseif-part
.. --->多個elseif
else
else-part
end;
3.3.2 while語句
while condition do
statements;
end;
3.3.3 repeat-until
repeat
statements;
until conditions;
這個可能比較眼生,其實類似c++的do..while語句,即運行statements直到conditions爲真。
3.3.4 for循環
3.3.4.1 數值for循環
for var=exp1,exp2,exp3 do
loop-part
end
for將用exp3作爲step從exp1(初始值)到exp2(終止值),執行loop-part。其中exp3可以省略,默認step=1.
3.3.4.2 範型for循環
遍歷表
for k in pairs(t) do print(k) end -- 遍歷表t中的所有元素
for i,v in ipairs(a) do print(v) end
--遍歷表a,i爲其索引,v爲其值。
3.3.5 break和return
這個語法與c++類似,break是用來退出控制語句,return是用來退出函數的。
注:在lua中,break和return必須在一個塊得結束部分出現,即它的後邊出現的必須是end、else、until,如果真的想要在某個語句位置使用它們,可以顯式的使用do..end來包含它們實現想要的功能。例:do return end;
4. 函數
4.1 函數的定義
function name (param)
return value
end;
4.2 多返回值
lua是允許返回多個值的,如果函數有多個返回值,則對變量的賦值按照3.1賦值裏邊規定的方式賦值。
例:
function foo0 end
function foo1 return 'a' end
function foo2 return 'a' 'b' end
x,y = foo2() -- x='a', y='b'
x = foo2() -- x='a', 返回值'b'廢棄
x,y,z = 10,foo2() -- x=10, y='a', z='b'、
x,y = foo0() -- x=nil, y=nil
x,y = foo1() -- x='a', y=nil
x,y,z = foo2() -- x='a', y='b', z=nil
4.3 可變參數
lua函數可以接受可變數目的參數,和C語言類似在函數參數列表中使用三點(...)表示函數有可變的參數。lua將函數的參數放在一個叫arg的表中,除了參數以外,arg表中還有一個域n表示參數的個數
例:
printResult = ""
function test(...)
print ("haveing " .. arg.n .. " param")
for i,v in ipairs(arg) do
printResult = printResult .. tostring(v)
end;
print (printResult)
end
test('a','b','c','d','e')
結果:
haveing 5 param
abcde
4.4 命名參數
lua的調用過程中,參數是依次把實參傳遞給相應的形參的。但如果有時候我們很難記清參數的前後順序,這個時候就可以使用命名參數。顧名思義,就是爲每個參數起一個名字,調用的時候,只需要爲這個名字的參數賦值即可。
例:
function rename (arg)
return os.rename(arg.old, arg.new)
end
rename(old="temp.lua", new="temp1.lua") –調用的時候爲命名參數賦值
4.5 閉包
首先明確一個概念,詞法定界。當一個函數內部嵌套另一個函數定義時,內部的函數體可以訪問外部的函數的局部變量,這種特徵我們稱作詞法定界
所謂“閉包”,官方解釋指的是一個擁有許多變量和綁定了這些變量的環境的表達式(通常是一個函數),因而這些變量也是該表達式的一部分。
是不是有點糊塗呢?舉個例子:
function newCounter()
local i = 0
return function() -- 無名函數
i = i + 1
return i
end
end
c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
c2 = newCounter()
print(c2()) --> 1
print(c1()) --> 3
print(c2()) --> 2
這段代碼有兩個特點,1. “匿名函數”嵌套在函數newCounter內,2. 函數newCounter把“匿名函數”返回了。
在執行完c1 = newCounter()後,其實c1指向的是“匿名函數”,當我們執行c1的時候,就可以操作函數newCounter的局部變量i,這個i我們稱之爲外部的局部變量(external local variable)或者upvalue。我們再次聲明一個變量c2= newCounter()後,c1和c2其實是建立在同一個函數上的,但是他們的局部變量i確是兩個不同的實例,即我們創建了兩個閉包。就是說:當函數newCounter的內部函數(即上例的“匿名函數”)被函數newCounter外的變量c1引用的時候,就創建了一個閉包。
閉包的應用場景:
- 保護函數內的變量安全。以最開始的例子爲例,函數a中i只有函數b才能訪問,而無法通過其他途徑訪問到,因此保護了i的安全性。
- 在內存中維持一個變量。依然如前例,由於閉包,函數a中i的一直存在於內存中,因此每次執行c(),都會給i自加1。
4.6 非全局函數
lua中函數可以作爲全局變量也可以作爲局部變量
1. 表和函數放在一起
Lib = {}
Lib.foo = function (x,y) return x + y end
Lib.goo = function (x,y) return x - y end
2. 使用表構造函數
Lib = {
foo = function (x,y) return x + y end,
goo = function (x,y) return x - y end
}
3. lua提供的另一種語法方式
Lib = {}
function Lib.foo (x,y)
return x + y
end
function Lib.goo (x,y)
return x - y
end
當我們將函數保存在一個局部變量內時,我們得到一個局部函數,也就是說局部函數像局部變量一樣在一定範圍內有效。定義局部函數的兩種方式:
local f = function (...)
...
end
local function f (...)
...
end
看如下代碼:
local fact = function (n)
if n == 0 then
return 1
else
return n*fact(n-1) -- 此處lua不能識別fact,因爲是局部函數,lua不能識別
end
end
修改爲先聲明,如下:
local fact
fact = function (n)
if n == 0 then
return 1
else
return n*fact(n-1)
end
end