lua快速入門~在js基礎上,知道Lua 和 Js 的不同即可

一樂樂發表於2023-04-04

☺ 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




如果本文對你有幫助的話記得給一樂點個贊哦,感謝!

相關文章