☺ lua 和 javaScript 差不多的,就是一些語法的細節不同,學過js,再注意一下下面的細節,就能上手了~
快速入門,可以直接看一下菜鳥教程的lua:https://www.runoob.com/lua/lua-tutorial.html
Lua 和 Js 的不同
Lua 概述
Lua概述
- Lua是一種輕量小巧的指令碼語言,用標準C語言編寫並以原始碼形式開放, 其設計目的是為了嵌入應用程式中,從而為應用程式提供靈活的擴充套件和定製功能。
Lua特性
1.輕量級
- 使用標準C語言編寫並以原始碼形式開放,編譯後僅僅一百餘K,可以很方便的嵌入別的程式裡。
2.可擴充套件
- Lua提供了非常易於使用的擴充套件介面和機制:由宿主語言(通常是C或C++)提供這些功能,Lua可以使用它們,就像是本來就內建的功能一樣。
3.其它特性
支援程式導向(procedure-oriented)程式設計和函式語言程式設計(functional programming)
自動記憶體管理;只提供了一種通用型別的表(table),用它可以實現陣列,雜湊表,集合,物件、字典,並且table是變長變數
語言內建模式匹配;閉包(closure);函式也可以看做一個值;提供多執行緒(協同程式,並非作業系統所支援的執行緒)支援
透過閉包和table可以很方便地支援物件導向程式設計所需要的一些關鍵機制,比如資料抽象,虛擬函式,繼承和過載等
1、註釋
(1) 單行註釋:
--
(2) 多行註釋:
--[[
多行註釋
多行註釋
--]]
2、變數
全域性變數:
- 預設情況下,沒有被local 修飾的變數都是全域性變數,不管它的位置在哪裡
- 訪問一個沒有初始化的全域性變數也不會出錯,只不過得到的結果是:nil
- 如果你想刪除一個全域性變數,只需要將變數賦值為nil。
區域性變數[私有
]
- local 修飾
nil (空)
字串
-
字串由一對雙引號或單引號來表示
-
也可以用 2 個方括號 "[[]]" 來表示"一塊"字串
string1 = "this is string1"
string2 = 'this is string2'
html = [[
<html>
<head></head>
<body>
<a href="http://www.runoob.com/">菜鳥教程</a>
</body>
</html>
]]
print(html)
☺ 字串拼接,使用的是 ..
-- 舉例子:
> print("a" .. 'b')
ab
> print(157 .. 428)
157428
加號 + ,這和java有區別,會把字串轉成數學的加分運算
-- 舉例子:
> print("2" + 6)
8.0
> print("2" + "6")
8.0
計算字串長度,使用#
> len = "www.runoob.com"
> print(#len)
3、迴圈語句、判斷語句
迴圈語句
(1) while
while(condition)
do
statements
end
(2) for
var 從 exp1 變化到 exp2,每次變化以 exp3 為步長遞增 var,並執行一次 "執行體"。exp3 是可選的,如果不指定,預設為1。
for var=exp1,exp2,exp3 do
<執行體>
end
-- 舉例子:
tab1 = { key1 = "val1", key2 = "val2", "val3" }
for k, v in pairs(tab1) do
print(k .. " - " .. v)
end
(3) repeate
repeat
statements
until( condition )
判斷語句
--[ 0 為 true ]
if(0)
then
print("0 為 true")
end
4、函式獲取可變引數的長度,也是使用#變數,或者使用select方法
-- 舉例子:
function average(...)
result = 0
local arg={...} --> arg 為一個表,區域性變數
for i,v in ipairs(arg) do
result = result + v
end
print("總共傳入 " .. #arg .. " 個數")
return result/#arg
end
print("平均值為",average(10,5,3,4,5,6))
-----------------------------------
function average(...)
result = 0
local arg={...}
for i,v in ipairs(arg) do
result = result + v
end
print("總共傳入 " .. select("#",...) .. " 個數")
return result/select("#",...)
end
print("平均值為",average(10,5,3,4,5,6))
5、select 方法
- select('#', …) 返回可變引數的長度。
- select(n, …) 用於返回從起點 n 開始到結束位置的所有引數列表
- 如果這時候使用一個變數指向方法 select(n, …),它只會得到第 n 位置的引數值
function f(...)
a = select(3,...) -->從第三個位置開始,變數 a 對應右邊變數列表的第一個引數
print (a)
print (select(3,...)) -->列印所有列表引數
end
f(0,1,2,3,4,5)
-- 結果:
2
2 3 4 5
6、lua 的運運算元
-
通用的加減乘除外,還有整除 // , 比如:5//2 輸出結果 2
-
不等於 ~=
-
邏輯運運算元:and、or、not
-
其他運運算元:
.. 連線兩個字串
# 一元運運算元,返回字串或表的長度
7、跳脫字元
所有的跳脫字元和所對應的意義:
跳脫字元 | 意義 | ASCII碼值(十進位制) |
---|---|---|
\a | 響鈴(BEL) | 007 |
\b | 退格(BS) ,將當前位置移到前一列 | 008 |
\f | 換頁(FF),將當前位置移到下頁開頭 | 012 |
\n | 換行(LF) ,將當前位置移到下一行開頭 | 010 |
\r | 回車(CR) ,將當前位置移到本行開頭 | 013 |
\t | 水平製表(HT) (跳到下一個TAB位置) | 009 |
\v | 垂直製表(VT) | 011 |
\ | 代表一個反斜線字元''' | 092 |
' | 代表一個單引號(撇號)字元 | 039 |
" | 代表一個雙引號字元 | 034 |
\0 | 空字元(NULL) | 000 |
\ddd | 1到3位八進位制數所代表的任意字元 | 三位八進位制 |
\xhh | 1到2位十六進位制所代表的任意字元 | 二位十六進位制 |
8、常用的字串函式
Lua 提供了很多的方法來支援字串的操作:
序號 | 方法 & 用途 |
---|---|
1 | string.upper(argument): 字串全部轉為大寫字母。 |
2 | string.lower(argument): 字串全部轉為小寫字母。 |
3 | string.gsub(mainString,findString,replaceString,num)在字串中替換。mainString 為要操作的字串, findString 為被替換的字元,replaceString 要替換的字元,num 替換次數(可以忽略,則全部替換),如:> string.gsub("aaaa","a","z",3); zzza 3 |
4 | string.find (str, substr, [init, [plain]]) 在一個指定的目標字串 str 中搜尋指定的內容 substr,如果找到了一個匹配的子串,就會返回這個子串的起始索引和結束索引,不存在則返回 nil。init 指定了搜尋的起始位置,預設為 1,可以一個負數,表示從後往前數的字元個數。plain 表示是否使用簡單模式,預設為 false,true 只做簡單的查詢子串的操作,false 表示使用使用正則模式匹配。以下例項查詢字串 "Lua" 的起始索引和結束索引位置:> string.find("Hello Lua user", "Lua", 1) 7 9 |
5 | string.reverse(arg) 字串反轉> string.reverse("Lua") auL |
6 | string.format(...) 返回一個類似printf的格式化字串> string.format("the value is:%d",4) the value is:4 |
7 | string.char(arg) 和 string.byte(arg[,int]) char 將整型數字轉成字元並連線, byte 轉換字元為整數值(可以指定某個字元,預設第一個字元)。> string.char(97,98,99,100) abcd > string.byte("ABCD",4) 68 > string.byte("ABCD") 65 > |
8 | string.len(arg) 計算字串長度。string.len("abc") 3 |
9 | string.rep(string, n) 返回字串string的n個複製> string.rep("abcd",2) abcdabcd |
10 | .. 連結兩個字串> print("www.runoob.".."com") www.runoob.com |
11 | string.gmatch(str, pattern) 返回一個迭代器函式,每一次呼叫這個函式,返回一個在字串 str 找到的下一個符合 pattern 描述的子串。如果引數 pattern 描述的字串沒有找到,迭代函式返回nil。> for word in string.gmatch("Hello Lua user", "%a+") do print(word) end Hello Lua user |
12 | string.match(str, pattern, init) string.match()只尋找源字串str中的第一個配對. 引數init可選, 指定搜尋過程的起點, 預設為1。 在成功配對時, 函式將返回配對錶達式中的所有捕獲結果; 如果沒有設定捕獲標記, 則返回整個配對字串. 當沒有成功的配對時, 返回nil。> = string.match("I have 2 questions for you.", "%d+ %a+") 2 questions > = string.format("%d, %q", string.match("I have 2 questions for you.", "(%d+) (%a+)")) 2, "questions" |
字串替換
string.gsub(mainString,findString,replaceString,num)在字串中替換。
- mainString 為要操作的字串, findString 為被替換的字元,replaceString 要替換的字元,num 替換次數(可以忽略,則全部替換)
string.gsub("aaaa","a","z",3)
- 結果:zzza 3
字串反轉
string.reverse(arg) 字串反轉
string.reverse("Lua")
> auL
字串長度
string.len(arg)
字串複製
string.rep(string, n)
返回字串string的n個複製
> string.rep("abcd",2)
abcdabcd
字串拼接,使用的是 ..
> print("www.runoob.".."com")
www.runoob.com
字串擷取
string.sub(s, i [, j]) 用於擷取字串,原型為:
引數說明:
- s:要擷取的字串。
- i:擷取開始位置。
- j:擷取結束位置,預設為 -1,最後一個字元。
print(string.sub("abcdef", 1, 3))
> abc
字串查詢
(1) string.find (str, substr, [init, [plain]])
在一個指定的目標字串 str 中搜尋指定的內容 substr,如果找到了一個匹配的子串,就會返回這個子串的起始索引和結束索引,不存在則返回 nil。
init 指定了搜尋的起始位置,預設為 1,可以一個負數,表示從後往前數的字元個數。
plain 表示是否使用簡單模式,預設為 false,true 只做簡單的查詢子串的操作,false 表示使用使用正則模式匹配。
以下例項查詢字串 "Lua" 的起始索引和結束索引位置:
> string.find("Hello Lua user", "Lua", 1)
7 9
(2) string.gmatch(str, pattern)
返回一個迭代器函式,每一次呼叫這個函式,返回一個在字串 str 找到的下一個符合 pattern 描述的子串。如果引數 pattern 描述的字串沒有找到,迭代函式返回nil。
> for word in string.gmatch("Hello Lua user", "%a+") do print(word) end
Hello
Lua
user
(3) string.match(str, pattern, init)
string.match()只尋找源字串str中的第一個配對. 引數init可選, 指定搜尋過程的起點, 預設為1。
在成功配對時, 函式將返回配對錶達式中的所有捕獲結果; 如果沒有設定捕獲標記, 則返回整個配對字串. 當沒有成功的配對時, 返回nil。
> = string.match("I have 2 questions for you.", "%d+ %a+")
2 questions
區別:使用format 格式化一下
> = string.format("%d, %q", string.match("I have 2 questions for you.", "(%d+) (%a+)"))
2, "questions"
9、正則匹配規則
和java 不一樣,可以到時候,使用lua 正則線上規則,檢查是否正確
字元 含義
%a 字母a-z,A-Z
%b %bxy,以x和y進行成對匹配
%c 控制字元ASCII碼 十進位制轉義表示為\0 - \31
%d 數字 0 - 9
%f %f[char-set],邊界匹配,前一個不在範圍內,後一個在
%g 除了空格以外的可列印字元 十進位制轉義表示為\33 - \126
%l 小寫字母 a - z
%u 大寫字母 A - Z
%s 空格 十進位制轉義表示為\32
%p 標點符號,即!@#$%^&*()`~-_=+{}:"<>?[];',./| 32個字元
%w 字母數字 a - z, A - Z, 0 - 9
%x 十六進位制符號 0 - 9, a - f, A - F
模糊匹配的其他匹配情況[單個字元(除 ^$()%.[]*+-? 外): 與該字元自身配對]:https://www.runoob.com/lua/lua-strings.html
10、字串格式化
Lua 提供了 string.format() 函式,以下是它的一些轉義碼:
%c - 接受一個數字, 並將其轉化為ASCII碼錶中對應的字元
%d, %i - 接受一個數字並將其轉化為有符號的整數格式
%o - 接受一個數字並將其轉化為八進位制數格式
%u - 接受一個數字並將其轉化為無符號整數格式
%x - 接受一個數字並將其轉化為十六進位制數格式, 使用小寫字母
%X - 接受一個數字並將其轉化為十六進位制數格式, 使用大寫字母
%e - 接受一個數字並將其轉化為科學記數法格式, 使用小寫字母e
%E - 接受一個數字並將其轉化為科學記數法格式, 使用大寫字母E
%f - 接受一個數字並將其轉化為浮點數格式
%g(%G) - 接受一個數字並將其轉化為%e(%E, 對應%G)及%f中較短的一種格式
%q - 接受一個字串並將其轉化為可安全被Lua編譯器讀入的格式
%s - 接受一個字串並按照給定的引數格式化該字串
11、字元與整數相互轉換
string.byte(字串) 轉換第一個字元
string.char(數字) 轉換為字元
12、Lua特性:自動記憶體管理;只提供了一種通用型別的表(table),用它可以實現陣列,雜湊表,集合,物件、字典,並且table是變長變數
table 變數注意事項:
table 的索引不可以是數字,也不可以是字串,會報錯,只能是普通變數
。
> tbl ={100 = "100"}
stdin:1: '}' expected near '='
> tbl ={"100" = "100"}
stdin:1: '}' expected near '='
-- 正確寫法:
> tbl = {a = "aa"}
> print(tbl["a"])
aa
> print(tbl.a)
aa
(1) 陣列
array = {}
for i= -2, 2 do
array[i] = i *2
end
for i = -2,2 do
print(array[i])
end
-
結果:
-4
-2
0
2
4
(2) Lua 迭代器
☺ 泛型迭代
pairs 和 ipairs異同
同:都能進行for 迴圈遍歷
異:ipairs 僅僅遍歷值,按照索引升序遍歷,索引中斷停止遍歷。即不能返回 nil,只能返回數字 0,如果遇到 nil 則退出。所以table 變數中的變數是鍵值對形式的,它會直接忽略,即ipairs 迭代時會略過非數值的索引。
pairs 能遍歷集合的所有元素。即 pairs 可以遍歷集合中所有的 key,並且除了迭代器本身以及遍歷表本身還可以返回 nil。
注意:下面兩個例子的結果的順序、特點
tab = {"Hello","World",a=1,b=2,z=3,x=10,y=20,"Good","Bye"}
for k,v in pairs(tab) do
print(k.." "..v)
end
- 結果:
1 Hello
2 World
3 Good
4 Bye
a 1
x 10
b 2
y 20
z 3
tab = {"Hello","World",a=1,b=2,z=3,x=10,y=20,"Good","Bye"}
for k,v in ipairs(tab) do
print(k.." "..v)
end
- 結果:
1 Hello
2 World
3 Good
4 Bye
如上程式碼輸出結果存在一定規律,"Hello"、"World"、"Good"、"Bye"是表中的值,在儲存時是按照順序儲存的,並且不同於其他指令碼語言,Lua是從1開始排序的,因此,使用pairs遍歷列印輸出時,會先按照順序輸出表的值,然後再按照鍵值對的鍵的雜湊值列印。
☺ 泛型迭代的例子2:
for k, v in pairs(t) do
print(k, v)
end
-------------------------------------------
array = {"Google", "Runoob"}
for key,value in ipairs(array)
do
print(key, value)
end
- 結果:
1 Google
2 Runoob
☺ 泛型 for 在迭代的時候每次呼叫的是閉包函式,迭代函式只是開始的時候呼叫一次
function eleiter(t)
local index = 0
print('in eleiter function') --> 每次呼叫迭代函式都說一句:in eleiter function
return function()
print('I am here.') --> 每次呼叫閉包函式都說一句:I am here
index = index + 1
return t[index]
end
end
t = {'one','two','three','four','five'}
for ele in eleiter(t) do
print(ele)
end
- 結果:
in eleiter function --> 【
for 迭代函式內部包含閉包函式的情況,對於函式非閉包內容,只執行一次
】-->
泛型 for 在迭代的時候每次呼叫的是閉包函式
I am here.
one
I am here.
two
I am here.
three
I am here.
four
I am here.
five
I am here.
(2) 表、字典、物件....
在lua使用 table 表示了陣列、表、字典、物件
table 特點:
Lua table 使用關聯型陣列,你可以用任意型別的值來作陣列的索引,但這個值不能是 nil。
Lua table 是不固定大小的,你可以根據自己需要進行擴容。
Lua 的table 變數是引用型變數,即地址指向。
tab = {"Hello","World",a=1,b=2,z=3,x=10,y=20,"Good","Bye"}
tab[1] = "W兩個世界"
for k,v in ipairs(tab) do
print(k.." "..v)
end
- 結果:
1 W兩個世界
2 World
3 Good
4 Bye
Lua 的table 變數是引用型變數,即地址指向。
-- 簡單的 table
mytable = {}
print("mytable 的型別是 ",type(mytable))
mytable[1]= "Lua"
mytable["wow"] = "修改前"
print("mytable 索引為 1 的元素是 ", mytable[1])
print("mytable 索引為 wow 的元素是 ", mytable["wow"])
-- alternatetable和mytable的是指同一個 table
alternatetable = mytable
print("alternatetable 索引為 1 的元素是 ", alternatetable[1])
print("mytable 索引為 wow 的元素是 ", alternatetable["wow"])
alternatetable["wow"] = "修改後"
print("mytable 索引為 wow 的元素是 ", mytable["wow"])
-- 釋放變數
alternatetable = nil
print("alternatetable 是 ", alternatetable)
-- mytable 仍然可以訪問
print("mytable 索引為 wow 的元素是 ", mytable["wow"])
mytable = nil
print("mytable 是 ", mytable)
- 結果:
mytable 的型別是 table
mytable 索引為 1 的元素是 Lua
mytable 索引為 wow 的元素是 修改前
alternatetable 索引為 1 的元素是 Lua
mytable 索引為 wow 的元素是 修改前
mytable 索引為 wow 的元素是 修改後
alternatetable 是 nil
mytable 索引為 wow 的元素是 修改後
mytable 是 nil
(3) table 的增刪改查操作
序號 | 方法 & 用途 |
---|---|
1 | table.concat (table [, sep [, start [, end]]]):concat是concatenate(連鎖, 連線)的縮寫. table.concat()函式列出引數中指定table的陣列部分從start位置到end位置的所有元素, 元素間以指定的分隔符(sep)隔開。 |
2 | table.insert (table, [pos,] value):在table的陣列部分指定位置(pos)插入值為value的一個元素. pos引數可選, 預設為陣列部分末尾. |
3 | table.maxn (table)指定table中所有正數key值中最大的key值. 如果不存在key值為正數的元素, 則返回0。(Lua5.2之後該方法已經不存在了,本文使用了自定義函式實現) |
4 | table.remove (table [, pos])返回table陣列部分位於pos位置的元素. 其後的元素會被前移. pos引數可選, 預設為table長度, 即從最後一個元素刪起。 |
5 | table.sort (table [, comp])對給定的table進行升序排序。 |
13、協同程式 coroutine
(1) 基本語法
方法 | 描述 |
---|---|
coroutine.create() | 建立 coroutine,返回 coroutine, 引數是一個函式,當和 resume 配合使用的時候就喚醒函式呼叫 |
coroutine.resume() | 重啟 coroutine,和 create 配合使用 |
coroutine.yield() | 掛起 coroutine,將 coroutine 設定為掛起狀態,這個和 resume 配合使用能有很多有用的效果 |
coroutine.status() | 檢視 coroutine 的狀態 注:coroutine 的狀態有三種:dead,suspended,running,具體什麼時候有這樣的狀態請參考下面的程式 |
coroutine.wrap() | 建立 coroutine,返回一個函式,一旦你呼叫這個函式,就進入 coroutine,和 create 功能重複 |
coroutine.running() | 返回正在跑的 coroutine,一個 coroutine 就是一個執行緒,當使用running的時候,就是返回一個 coroutine 的執行緒號 |
當create一個coroutine的時候就是在新執行緒中註冊了一個事件。
當使用resume觸發事件的時候,create的coroutine函式就被執行了,當遇到yield的時候就代表掛起當前執行緒,等候再次resume觸發事件。
可以把 yield 當成暫時,點選resume 當成開始,並且具有“斷點續傳” 作用
-- 註冊一個事件
co = coroutine.create(
function(i)
print(coroutine.status(co))
-- 掛起/暫停
coroutine.yield()
print(i);
end
)
-- 執行事件
coroutine.resume(co, 1)
print(coroutine.status(co))
coroutine.resume(co, 3) -- 重新開始,相當於“斷點續傳”,因為這時候傳遞引數已經是3,但在原先情況上繼續執行,會執行coroutine.resume(co, 1) 的引數1
- 結果:
running
suspended
1
(2) coroutine.creat方法和coroutine.wrap 的區別
- 返回值不同:coroutine.creat返回的是一個協同程式,型別為thread,需要使用coroutine.resume進行呼叫;而coroutine.wrap返回的是一個普通的方法(函式),型別為function,和普通function有同樣的使用方法,並且不能使用coroutine.resume進行呼叫。
co_creat = coroutine.create(
function()
print("co_creat型別是"..type(co_creat))
end
)
co_wrap = coroutine.wrap(
function()
print("co_wrap型別是"..type(co_wrap))
end
)
coroutine.resume(co_creat)
co_wrap()
- 結果:
co_creat型別是thread
co_wrap型別是function
14、建立物件
Lua 中使用":"實現物件導向方式的呼叫。":"只是語法糖,它同時在方法的宣告與實現中增加了一個名為 self 的隱藏引數,這個引數就是物件本身。
- --例項:
Account = {balance = 0};
--生成物件
function Account:new(o)
o = o or {}; --如果使用者沒有提供物件,則建立一個。
setmetatable(o, self); --將 Account 作為新建立的物件元表
self.__index = self; --將新物件元表的 __index 指向為 Account(這樣新物件就可以透過索引來訪問 Account 的值了)
return o; --將新物件返回
end
--存款
function Account:deposit(v)
self.balance = self.balance + v;
end
--取款
function Account:withdraw(v)
self.balance = self.balance - v;
end
--查詢
function Account:demand()
print(self.balance);
end
--建立物件
myAccount = Account:new();
--透過索引訪問
print(myAccount.balance);
--呼叫函式
myAccount:deposit(100);
myAccount:withdraw(50);
myAccount:demand();
-
結果:
0
50
如果本文對你有幫助的話記得給一樂點個贊哦,感謝!