1. 程式人生 > >Lua學習筆記

Lua學習筆記

最近準備把lua應用到之前寫過的Unity專案中,所以先學一下Lua,在這裡做點筆記,自己沒事翻翻看就好。

lua學習記錄

lua的變數型別 nil string number boolean  table(“表”,lua的面向物件由表實現) function userdata thread(表示執行的獨立執行緒,本質是偽“多執行緒”,是協程的概念,用於執行協同程式)

判斷語句短路規則

真&&假   假
假&&真   假
num1&&num2  num2

真||假   真
假||真   真
num1||num2  num1

多重賦值  num1,num2,num3 = 10,20,30

在語句塊中新增local才是區域性變數
eg.
 do
   local num = 1 (區域性變數)
 end

ipairs與pairs迭代器

ipairs迭代陣列、遍歷順序集合,遇到nil就會中斷
pairs迭代表、遍歷集合中的所有資料
使用pairs關鍵字,迴圈輸出資料、字串型別時,for中必須使用k、v,迴圈中的k、v可以是任何字母或者合法的識別符號代替

lua標準庫提供的迭代器
A.迭代檔案每行的io.lines
B.迭代table的pairs
C.迭代陣列元素得的ipairs
D.迭代字串中單詞的string.gmatch


lua函式function
函式格式
function function_name( ... )
	-- body
end

lua函式的性質
1.函式無需定義返回型別,可以返回任意型別與任意數量的數值
2.函式的引數,無需定義引數型別
3.函式無需大括號
4.可以定義變數,把函式直接賦值給它,從而獲得相同功能(類似與C#的委託)

eg.
1.不帶返回值 
function func1(a)

end
2.帶返回值
function func2( a,b)
	return a+b
end
3.函式賦值給變數 
func3 = func2
--因為func2有返回值
result1 = func3(20,30)
print(""..result1)

warning:定義函式  函式中由於函式沒有引數型別,所以在沒有(編譯)執行前,計算機是無法發現錯誤的,這對比其他編譯語言是一個明顯的弱點


local關鍵字,全域性與區域性變數
lua規定,預設變數都是全域性變數(無論是否定義在語句塊中),區域性變數需要在程式碼塊中用local修飾
eg.
function func4(  )
	gNum1 = 10         --全域性變數num1
	local num2 = 20   --使用local定義區域性變數num2   
end

fun4()
print(gNum1)    --輸出10
print(num2)     --報錯無法輸出,num2是nil值

在函式中定義全域性變數,在函式外照樣可以訪問
函式可以宣告為全域性的與區域性的,預設是全域性的
eg.
local function locFunc( ... )
	-- body
end	
local函式不能被別的lua檔案呼叫,類似於類中的private方法

函式的多返回值
可以返回多個任意不同型別的數值
eg.
function GetNumb( ... )
	return 10,20,30,(40)
end
res1,res2,res3,(res4)  = GetNumb()
函式的多返回值性質:
1.如果一個函式呼叫在最後,或者僅有一個表示式,lua回保留儘可能多的返回數值用於匹配
2.如果一個函式沒有返回值,或者沒有足夠多的返回值,那麼lua會用nul來補充缺失數值

函式可以作為資料進行賦值,也可以作為引數進行傳遞(類似於C#的委託)
函式作為引數進行傳遞
eg.
function PrintInfo( res )
	print("")
	print(res)
end
function AddNum(num1,num2,printFunc)
	local result = num1+num2
    printFunc(result)
end

匿名函式
定義:沒有函式名稱的函式
一個沒有名稱的函式,只有通過賦值給一個變數(相當於C#的委託註冊方法),通過呼叫這個函式變數來間接呼叫這個匿名函式
定義的時候,無需定義函式名稱,但是一定要把匿名函式賦值給變數
eg.
hideFunc = function (num1,num2)
	--匿名函式
	print(num1+num2)
end

hideFunc(66,88) --呼叫匿名函式,本質是呼叫的是匿名函式賦值給的變數

Lua字串

字串的下標從1開始

字串的三種表示方式
str1= "   "
str2= '   '
str3=[[   ]]   --適合大量字串
str4="   '  '  "  --可以在雙引號裡面帶單引號
str5='  "   "   '--單引號裡面可以帶雙引號

string.len(str1)  --使用字串函式,輸出字串長度
#str2      --使用#符號,輸出字串長度

轉義字串
常用的,回車 \r   換行 \n    反斜槓 \\     雙引號 ""

字串常用函式
A:字串長度len()、大小寫函式upper()、lower()
string.len(str)
string.upper(str)
string.lower(str)

B:查詢函式find()
string.find(s,pattern,init,plain)
findPos = string.find(str,"a")   --str是搜尋的源字串,"a"表示搜尋關鍵字
findPos = string.find(str,"a",5) --"5"引數表示從下標5的位置開始搜尋

C:擷取函式 sub()
string.sub(s,i,j) --s是源字串,i是選擇擷取字串的位置,j是擷取j個字元
strSubResult = string.sub("HelloWorld",1,3)
strSubResult = string.sub("朋友們好,Hello!",1,4)  --漢字是兩個佔位符

D:字串替換函式 gsub()
strGSubResult = string.gsub(s,pattern,repl,n) --s源字串,pattern關鍵字,repl替換後的關鍵字,n

E:字串反轉 reverse()
strReverseResult = string.reverse(s)  --s源字串
--> abcd  ==> dcba

F:格式化字串 format()

傳統輸出多個變數的長字串,使用“拼接”的方式
eg.
num1,num2,num3 = 10,20,30
--輸出三個變數相加的結果
print("加法:num1:"..num1.." +num2"..num2.." +num3:"..num3.." result="..num1+num2+num3)

訪問資料庫的開發
print("select 列名? from 表明? where id = ?查詢條件? and ...")  --查詢資料庫的語句

--簡化以上長字串中新增多個變數問題的寫法,lua提供了“字串格式化”函式
eg.
--%d 表示一個數值型變數
--%s 表示一個字串變數
string.format()
strFormatResult = string.format(formatstring:"使用字串格式化:num1: %d+num2: %d+num3: %d = result: %d",num1,num2,num3,num1+num2+num3)   --formatstring需要格式化的字串

表
 Table是lua的一種資料結構,用來幫助我們建立不同的資料型別,如陣列、鍵值對集合等。。

表的特徵與定義
lua(陣列)的下標可以是負數,lua的長度可以動態改變(與C#的固定長度陣列不同),可以把lua陣列認為是C#的List、dictionary等集合型別
把Table當成一個"字典"集合來對待,也可以當成一個"陣列"來對待,這要看如何初始化表

Table集合,可以有“空表”,“直接宣告且定義表內容”,“宣告表然後逐一賦值”三種方式
Table集合,也可以定義成類似“陣列”的定義方式,其訪問可以使用下標進行訪問(但是lua沒有陣列概念,用表來表示)
訪問table中的資料(鍵值對集合),可以直接用“.”訪問,也可以用中括號訪問,但一定要加字串,否則會報錯
Table中的索引都是由1開始的

tabMyArray = {}    --定義表
print(tabMyArray)   --輸出表的地址
--定義陣列型別的表
tabMyArray1 = {11,111,333}   --相當於陣列
print(tabMyArray1[1])  --使用下標,進行表的內容輸出 
print(tabMyArray1[2])
print(tabMyArray1[3])
--下標是從1開始的   要是tabMyArray1[0] 則會輸出nil

--定義鍵值對型別的表
tabMyArray3 = {str1="aaa",str2="bbb",str3="ccc"}
--輸出鍵值對型別的表
--兩種不同的輸出方式
1.使用中括號輸出
print(tabMyArray3["str1"]) --輸出資訊
2.使用“.”輸出,類似於C#中輸出屬性
print(tabMyArray3.str2)
print(tabMyArray3.str3)

表的賦值與迭代輸出
1.空表的賦值與迭代輸出 --空表要賦值才能輸出
2.字典型別表的賦值與迭代輸出
3.關於表變數的相互賦值的技術(引用傳遞)

lua中的table相當於c#中的字典類集合(具備key/value鍵值對的資料結構)
lua表的遍歷方式
[table.getn();表示集合中的數量,即集合中最大索引]
for i =1,table.getn(mytable) do 
	...
end

for i,v in pairs(mytable) do
	print(i,v)
end

tabMyArray4 = {10,20,30,54,40}
--使用for輸出  
for i =1 ,4 do
	print(tabMyArray4[i])
end
--使用table函式或者符號輸出
for i =1 ,#tabMyArray4 do    --使用“#”符號,來得到表中的數量
	print(tabMyArray4[i])
end

for i=1 , table.getn(tabMyArray4) do    --使用表函式table.getn(tableName),得到表中的數量
	print(tabMyArray4[i])
end

--使用迭代輸出(鍵值對型別)
tabMyArray5= {str1="aaa",str2="bbb",str3="ccc"}
tabMyArray5.str4 = "ddd"
tabMyArray5["str5"] = "eee"
--輸出
for i =1,5 do --需要注意,getn和 # 只能用於陣列,鍵值對還是需要給定長度   
	print(tabMyArray5["str"..i])   --不常用也不實用
end

使用迭代器函式 pairs / ipairs 輸出連續與非連序(鍵值對)數值
 --輸出順序不能保證
 tabMyArray6 = {str1="aaa",str2="bbb",str3="ccc"}   
 for k,v in pairs(tabMyArray6) do
 	print(k,v)   --k鍵   v值   --key value
 end

 一般陣列型別的集合可以只輸出v,即只輸出資料,但是 k,v還是必須的。
 tabMyArray7={"aa","bbb","c"}
 for k,v in ipairs(tabMyArray7) do
 	print(v)
 end

 表的函式

 table.getn():得到表(陣列型)的長度
tab1= {"aa","bbb","c"}
得到表的長度   # 和table.getn都可以都可以得到陣列型表的長度
eg.
print(#tab1)
print(table.getn(tab1))


 table.concat():高效率的對於字串連結的一種方式
 eg.
 tab2 = {"aa","bbb","c"}
 str2 = table.concat(tab2)
 print("str2="..str2)   --print : str2=aabbbc
 str3 = table.concat(tab2,"|")   --新增分隔符
 print("str3="..str3)   --print : str2=aa|bbb|c
 str4 = table.concat(tab2,"|",2,3)   --指定序號內容字串 2到3
 print("str4="..str4)   --print : str2=bbb|c

 table.insert(t,pos,value)  --t表,pos位置,value值
eg.
tab3 = {"Hell","Every"}
table.insert(tab3,2,"o ")
print(table.concat( tab3))   --print : Hello Every

tab4 = {"同學","大家好"}
table.insert(tab4,2,"們,")
print(table.concat( tab4))   --print : 同學們,大家好


 table.remove()
 tab5 = {"Hello ","Everyone","OK"}
 table.remove(tab5)    --函式預設移除最後的字串序號
  print(table.concat( tab5))   --print :Hello Everyone
  table.remove(tab5,2)   --這樣就把Everyone刪除了
 print(table.concat( tab5))    --print :Hello OK

table.sort() 表的排序方法
needSortTable = {10,32,21,54,97,84,32,45,8}
table.sort( needSortTable )   --升序排列
--輸出檢視
for i =1,table.getn(needSortTable) do
	print(needSortTable[i])
end
--字串排序
needSortStrTable = {"river","sky","Cave","好","World"}
table.sort(needSortStrTable)
for i=1,table.getn(needSortStrTable) do 
	print(needSortStrTable[i])  --print :Cave World river sky 好   順序是大寫 小寫 中文
end

得到表中最大數值 lua 5.1好像有bug
table.maxn() 得到表中的最大正數索引值,返回的是key值
 tabMaxAarry = {10,32,21,54,97,84,32,45,8}
nMaxNum = table.maxn(tabMaxAarry)
print("表中最大數值 = "..nMaxNum)

尋找最大值函式
---輸入:tableName,表型別變數 (如果不合法則輸出nil)
---輸出:表中的最大值key值,以及對應的value
function GetTableMaxNumb(tableName)
	--建議在函式塊內使用區域性變數
	local returnMaxNumber = nil   --返回最大數值

	--引數檢查
	if(type(tableName)~="table") then    --type()返回值是個字串
		print("error table")
		return nil
	end

	for k,v in pairs(table) do		
	--給returnMaxNumber變數賦予初始數值
		if(returenMaxNumber ==nil) then
			returnMaxNumber = v
		end
		--取得表中得最大數值
		if(v>returnMaxNumber) then
			returnMaxNumber = v
		end
	end

	return returnMaxNumber
end

resultMaxNum = GetTableMaxNumb(tabMaxAarry)

if(resultMaxNum~=nil) then
	print(resultMaxNum)
else
	print("nil")
end

表資源的釋放
使用nil對錶(字串、基本其他資料型別)資源作釋放
給整個table賦值nil,則表示銷燬整個表,清空記憶體

tabMaxAarry = nil --釋放變數資源
resultMaxNum = nil 

lua模擬面向物件程式設計
OOP三大特性,封裝,繼承,多型
封裝:指能夠把一個實體的資訊、功能、響應都裝入一個單獨的物件中的特性
繼承:繼承的方法允許在不改動源程式的基礎上對其進行擴充,這樣使得原功能得以儲存,而新功能也得以擴充套件。有利於減少重複編碼,提高軟體的開發效率
多型:同一操作作用於不同的物件,可以有不同的解釋,產生不同的執行結果

lua的語法沒有面向物件機制
lua中使用Table實現面向物件機制。把table模擬成一個“類”來使用。

其實lua的string(math、random)等就可以看成面向物件的特殊表

定義表的欄位與方法
tableName.field 定義表的欄位與方法使用
tableName.methodName()定義表的欄位與方法
定義表的第二種方式,匿名方法賦值給表字段

eg.  --定義一個空表,相當於一個OOP程式設計中得“類”
Person = {}

--定義欄位  
Person.Name = "陳治翰"
Person.Gender = "男"
Person.Weight = 51
Person.Height = 173
--定義方法   
Person.Speak = function ( ) ---第一種定義方式  匿名函式
	print("人在說話")
end

function Person.Walking()   --第二種定義方式  常用的定義方法
	print("人在走路")
end

--在方法中呼叫資訊 傳統定義方式
Person.ShowInfo = function (  )   
	print("呼叫個人資訊")
	print("身高"..Person.Height)   --記得要加Person
	print("體重"..Person.Weight)
	Person.Speak()
	person.Walking()
end
--在方法中呼叫資訊 改進函式定義方式使用區域性變數
--引入this變數
local this = Person
Person.ShowInfo = function (  )   
	print("呼叫個人資訊")
	print("身高"..this.Height)   --記得要加Person
	print("體重"..this.Weight)
	this.Speak()
	this.Walking()
end



呼叫表中"欄位"與"方法"
--呼叫欄位
print(Person.Name)   --print :陳治翰
print(Person.Gender) --print :男
print(Person.Weight) --print :51
print(Person.Height) --print :173

--呼叫方法
Person.Speak()
Person.Walking()

--提高函式的靈活性
a=Person   --把Person表複製給a 變數
a.ShowInfo()  --也可以執行的

Person=nil   --把Person銷燬了
a.ShowInfo()  --會報錯,Person是空物件
--要是定義了local this = Person
a.ShowInfo()  --正常執行了

表字段的缺陷
定義區域性表引用變數,降低方法引用表字段的耦合性  --使用self關鍵字 就可以不使用區域性變量了

在lua中,可以認為定義的Person表,Person是一個指標,那麼定義的Person表的內容在記憶體的其他區域。當Person賦值給a,就相當於又定義了一個a指標,就相當於有a、Person兩個指標指向Person的內容,
當Person = nil 只是把Person這個指標銷燬了,但是Person中的內容還在。在銷燬之前,使用a獲取Person的內容,則需要定義一個其他區域性變數,相當於第三個指標,該指標指向Person的內容。但是在Person表中,
需要用第三個指標呼叫Person的欄位和函式

使用self關鍵字完善方法定義和呼叫方式
使用self關鍵字,直接在方法中引用表自身的欄位與方法
--在方法中呼叫資訊 繼續改進函式定義方式使用區域性變數(配合函式使用“冒號”定義函式)
--使用自帶的self關鍵字
function Person:Show( )
	print("呼叫個人資訊")
	print("身高"..self.Height)   --記得要加Person
	print("體重"..self.Weight)
	self.Speak()
	self.Walking()
end
--呼叫
Person:Show()  --更加完善與常用的方法的呼叫方式