Lua 循環
很多情況下我們需要做一些有規律性的重複操作,因此在程序中就需要重複執行某些語句。
一組被重複執行的語句稱之爲循環體,能否繼續重複,決定循環的終止條件。
循環結構是在一定條件下反覆執行某段程序的流程結構,被反覆執行的程序被稱爲循環體。
循環語句是由循環體及循環的終止條件兩部分組成的。
Lua 語言提供了以下幾種循環處理方式:
循環類型 | 描述 |
---|---|
while 循環 | 在條件爲 true 時,讓程序重複地執行某些語句。執行語句前會先檢查條件是否爲 true。 |
for 循環 | 重複執行指定語句,重複次數可在 for 語句中控制。 |
repeat...until | 重複執行循環,直到 指定的條件爲真時爲止 |
循環嵌套 | 可以在循環內嵌套一個或多個循環語句(while do ... end;for ... do ... end;repeat ... until;) |
循環控制語句
循環控制語句用於控制程序的流程, 以實現程序的各種結構方式。
Lua 支持以下循環控制語句:
控制語句 | 描述 |
---|---|
break 語句 | 退出當前循環或語句,並開始腳本執行緊接着的語句。 |
goto 語句 | 將程序的控制點轉移到一個標籤處。 |
無限循環
在循環體中如果條件永遠爲 true 循環語句就會永遠執行下去,以下以 while 循環爲例:
實例
while( true )
do
print("循環將永遠執行下去")
end
Lua 流程控制
Lua 編程語言流程控制語句通過程序設定一個或多個條件語句來設定。在條件爲 true 時執行指定程序代碼,在條件爲 false 時執行其他指定代碼。
以下是典型的流程控制流程圖:
控制結構的條件表達式結果可以是任何值,Lua認爲false和nil爲假,true和非nil爲真。
要注意的是Lua中 0 爲 true:
--[ 0 爲 true ]
if(0)
then
print("0 爲 true")
end
以上代碼輸
出結果爲:
0 爲 true
Lua 提供了以下控制結構語句:
語句 | 描述 |
---|---|
if 語句 | if 語句 由一個布爾表達式作爲條件判斷,其後緊跟其他語句組成。 |
if...else 語句 | if 語句 可以與 else 語句搭配使用, 在 if 條件表達式爲 false 時執行 else 語句代碼。 |
if 嵌套語句 | 你可以在if 或 else if中使用一個或多個 if 或 else if 語句 。 |
Lua 函數
在Lua中,函數是對語句和表達式進行抽象的主要方法。既可以用來處理一些特殊的工作,也可以用來計算一些值。
Lua 提供了許多的內建函數,你可以很方便的在程序中調用它們,如print()函數可以將傳入的參數打印在控制檯上。
Lua 函數主要有兩種用途:
- 1.完成指定的任務,這種情況下函數作爲調用語句使用;
- 2.計算並返回值,這種情況下函數作爲賦值語句的表達式使用。
--[[ 函數返回兩個值的最大值 --]]
function max(num1, num2)
if (num1 > num2) then
result = num1;
else
result = num2;
end
return result;
end
-- 調用函數
print("兩值比較最大值爲 ",max(10,4))
print("兩值比較最大值爲 ",max(5,6))
Lua 中我們可以將函數作爲參數傳遞給函數,如下實例:
myprint = function(param)
print("這是打印函數 - ##",param,"##")
end
function add(num1,num2,functionPrint)
result = num1 + num2
-- 調用傳遞的函數參數
functionPrint(result)
end
myprint(10)
-- myprint 函數作爲參數傳遞
add(2,5,myprint)
多返回值
Lua函數可以返回多個結果值,比如string.find,其返回匹配串"開始和結束的下標"(如果不存在匹配串返回nil)。
> s, e = string.find("www.runoob.com", "runoob")
> print(s, e)
5 10
Lua函數中,在return後列出要返回的值的列表即可返回多值,如:
function maximum (a)
local mi = 1 -- 最大值索引
local m = a[mi] -- 最大值
for i,val in ipairs(a) do
if val > m then
mi = i
m = val
end
end
return m, mi
end
print(maximum({8,10,23,12,5}))
23 3
可變參數
Lua 函數可以接受可變數目的參數,和 C 語言類似,在函數參數列表中使用三點 ... 表示函數有可變的參數。
function add(...)
local s = 0
for i, v in ipairs{...} do --> {...} 表示一個由所有變長參數構成的數組
s = s + v
end
return s
end
print(add(3,4,5,6,7)) --->25
我們可以將可變參數賦值給一個變量。
例如,我們計算幾個數的平均值:
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))
總共傳入 6 個數
平均值爲 5.5
通常在遍歷變長參數的時候只需要使用 {…},然而變長參數可能會包含一些 nil,那麼就可以用 select 函數來訪問變長參數了:select('#', …) 或者 select(n, …)
調用select時,必須傳入一個固定實參selector(選擇開關)和一系列變長參數。如果selector爲數字n,那麼select返回它的第n個可變實參,否則只能爲字符串"#",這樣select會返回變長參數的總數。例子代碼:
select('#', …) 返回可變參數的長度
select(n, …) 用於訪問 n 到 select('#',…) 的參數
do
function foo(...)
for i = 1, select('#', ...) do -->獲取參數總數
local arg = select(i, ...); -->讀取參數
print("arg", arg);
end
end
foo(1, 2, 3, 4);
end
arg 1
arg 2
arg 3
arg 4
Lua 運算符
運算符是一個特殊的符號,用於告訴解釋器執行特定的數學或邏輯運算。Lua提供了以下幾種運算符類型:
- 算術運算符
- 關係運算符
- 邏輯運算符
- 其他運算符
操作符 | 描述 | 實例 |
---|---|---|
+ | 加法 | A + B 輸出結果 30 |
- | 減法 | A - B 輸出結果 -10 |
* | 乘法 | A * B 輸出結果 200 |
/ | 除法 | B / A w輸出結果 2 |
% | 取餘 | B % A 輸出結果 0 |
^ | 乘冪 | A^2 輸出結果 100 |
- | 負號 | -A 輸出結果 -10 |
a = 21
b = 10
c = a + b
print("Line 1 - c 的值爲 ", c )
c = a - b
print("Line 2 - c 的值爲 ", c )
c = a * b
print("Line 3 - c 的值爲 ", c )
c = a / b
print("Line 4 - c 的值爲 ", c )
c = a % b
print("Line 5 - c 的值爲 ", c )
c = a^2
print("Line 6 - c 的值爲 ", c )
c = -a
print("Line 7 - c 的值爲 ", c )
關係運算符
下表列出了 Lua 語言中的常用關係運算符,設定 A 的值爲10,B 的值爲 20:
操作符 | 描述 | 實例 |
---|---|---|
== | 等於,檢測兩個值是否相等,相等返回 true,否則返回 false | (A == B) 爲 false。 |
~= | 不等於,檢測兩個值是否相等,相等返回 false,否則返回 true | (A ~= B) 爲 true。 |
> | 大於,如果左邊的值大於右邊的值,返回 true,否則返回 false | (A > B) 爲 false。 |
< | 小於,如果左邊的值大於右邊的值,返回 false,否則返回 true | (A < B) 爲 true。 |
>= | 大於等於,如果左邊的值大於等於右邊的值,返回 true,否則返回 false | (A >= B) 返回 false。 |
<= | 小於等於, 如果左邊的值小於等於右邊的值,返回 true,否則返回 false | (A <= B) 返回 true。 |
a = 21
b = 10
if( a == b )
then
print("Line 1 - a 等於 b" )
else
print("Line 1 - a 不等於 b" )
end
if( a ~= b )
then
print("Line 2 - a 不等於 b" )
else
print("Line 2 - a 等於 b" )
end
if ( a < b )
then
print("Line 3 - a 小於 b" )
else
print("Line 3 - a 大於等於 b" )
end
if ( a > b )
then
print("Line 4 - a 大於 b" )
else
print("Line 5 - a 小於等於 b" )
end
-- 修改 a 和 b 的值
a = 5
b = 20
if ( a <= b )
then
print("Line 5 - a 小於等於 b" )
end
if ( b >= a )
then
print("Line 6 - b 大於等於 a" )
end
邏輯運算符
下表列出了 Lua 語言中的常用邏輯運算符,設定 A 的值爲 true,B 的值爲 false:
操作符 | 描述 | 實例 |
---|---|---|
and | 邏輯與操作符。 若 A 爲 false,則返回 A,否則返回 B。 | (A and B) 爲 false。 |
or | 邏輯或操作符。 若 A 爲 true,則返回 A,否則返回 B。 | (A or B) 爲 true。 |
not | 邏輯非操作符。與邏輯運算結果相反,如果條件爲 true,邏輯非爲 false。 | not(A and B) 爲 true。 |
a = true
b = true
if ( a and b )
then
print("a and b - 條件爲 true" )
end
if ( a or b )
then
print("a or b - 條件爲 true" )
end
print("---------分割線---------" )
-- 修改 a 和 b 的值
a = false
b = true
if ( a and b )
then
print("a and b - 條件爲 true" )
else
print("a and b - 條件爲 false" )
end
if ( not( a and b) )
then
print("not( a and b) - 條件爲 true" )
else
print("not( a and b) - 條件爲 false" )
end
其他運算符
下表列出了 Lua 語言中的連接運算符與計算表或字符串長度的運算符:
操作符 | 描述 | 實例 |
---|---|---|
.. | 連接兩個字符串 | a..b ,其中 a 爲 "Hello " , b 爲 "World", 輸出結果爲 "Hello World"。 |
# | 一元運算符,返回字符串或表的長度。 | #"Hello" 返回 5 |
a = "Hello "
b = "World"
print("連接字符串 a 和 b ", a..b )
print("b 字符串長度 ",#b )
print("字符串 Test 長度 ",#"Test" )
print("菜鳥教程網址長度 ",#"www.runoob.com" )
Lua 字符串
字符串或串(String)是由數字、字母、下劃線組成的一串字符。
Lua 語言中字符串可以使用以下三種方式來表示:
- 單引號間的一串字符。
- 雙引號間的一串字符。
- [[和]]間的一串字符。
以上三種方式的字符串實例如下:
string1 = "Lua"
print("\"字符串 1 是\"",string1)
string2 = 'runoob.com'
print("字符串 2 是",string2)
string3 = [["Lua 教程"]]
print("字符串 3 是",string3)
string1 = "Lua"
print("\"字符串 1 是\"",string1)
string2 = 'runoob.com'
print("字符串 2 是",string2)
string3 = [["Lua 教程"]]
print("字符串 3 是",string3)
轉義字符用於表示不能直接顯示的字符,比如後退鍵,回車鍵,等。如在字符串轉換雙引號可以使用 "\""。
所有的轉義字符和所對應的意義:
轉義字符 |
意義 |
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位十六進制所代表的任意字符 |
二位十六進制 |
字符串的操作
序號 | 方法 & 用途 |
---|---|
1 | string.upper(argument): 字符串全部轉爲大寫字母。 |
2 | string.lower(argument): 字符串全部轉爲小寫字母。 |
3 | string.gsub(mainString,findString,replaceString,num)
在字符串中替換。 mainString 爲要操作的字符串, findString 爲被替換的字符,replaceString 要替換的字符,num 替換次數(可以忽略,則全部替換),如:
|
4 | string.find (str, substr, [init, [end]]) 在一個指定的目標字符串中搜索指定的內容(第三個參數爲索引),返回其具體位置。不存在則返回 nil。
|
5 | string.reverse(arg) 字符串反轉
|
6 | string.format(...) 返回一個類似printf的格式化字符串
|
7 | string.char(arg) 和 string.byte(arg[,int]) char 將整型數字轉成字符並連接, byte 轉換字符爲整數值(可以指定某個字符,默認第一個字符)。
|
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" |
字符串格式化輸出
Lua 提供了 string.format() 函數來生成具有特定格式的字符串, 函數的第一個參數是格式 , 之後是對應格式中每個代號的各種數據。
由於格式字符串的存在, 使得產生的長字符串可讀性大大提高了。這個函數的格式很像 C 語言中的 printf()。
以下實例演示瞭如何對字符串進行格式化操作:
格式字符串可能包含以下的轉義碼:
- %c - 接受一個數字, 並將其轉化爲ASCII碼錶中對應的字符
- %d, %i - 接受一個數字並將其轉化爲有符號的整數格式
- %o - 接受一個數字並將其轉化爲八進制數格式
- %u - 接受一個數字並將其轉化爲無符號整數格式
- %x - 接受一個數字並將其轉化爲十六進制數格式, 使用小寫字母
- %X - 接受一個數字並將其轉化爲十六進制數格式, 使用大寫字母
- %e - 接受一個數字並將其轉化爲科學記數法格式, 使用小寫字母e
- %E - 接受一個數字並將其轉化爲科學記數法格式, 使用大寫字母E
- %f - 接受一個數字並將其轉化爲浮點數格式
- %g(%G) - 接受一個數字並將其轉化爲%e(%E, 對應%G)及%f中較短的一種格式
- %q - 接受一個字符串並將其轉化爲可安全被Lua編譯器讀入的格式
- %s - 接受一個字符串並按照給定的參數格式化該字符串
爲進一步細化格式, 可以在%號後添加參數. 參數將以如下的順序讀入:
- (1) 符號: 一個+號表示其後的數字轉義符將讓正數顯示正號. 默認情況下只有負數顯示符號.
- (2) 佔位符: 一個0, 在後面指定了字串寬度時佔位用. 不填時的默認佔位符是空格.
- (3) 對齊標識: 在指定了字串寬度時, 默認爲右對齊, 增加-號可以改爲左對齊.
- (4) 寬度數值
- (5) 小數位數/字串裁切: 在寬度數值後增加的小數部分n, 若後接f(浮點數轉義符, 如%6.3f)則設定該浮點數的小數只保留n位, 若後接s(字符串轉義符, 如%5.3s)則設定該字符串只顯示前n位.
string.format("%c", 83) -- 輸出S
string.format("%+d", 17.0) -- 輸出+17
string.format("%05d", 17) -- 輸出00017
string.format("%o", 17) -- 輸出21
string.format("%u", 3.14) -- 輸出3
string.format("%x", 13) -- 輸出d
string.format("%X", 13) -- 輸出D
string.format("%e", 1000) -- 輸出1.000000e+03
string.format("%E", 1000) -- 輸出1.000000E+03
string.format("%6.3f", 13) -- 輸出13.000
string.format("%q", "One\nTwo") -- 輸出"One\
-- Two"
string.format("%s", "monkey") -- 輸出monkey
string.format("%10s", "monkey") -- 輸出 monkey
string.format("%5.3s", "monkey") -- 輸出 mon
字符與整數相互轉換
以下實例演示了字符與整數相互轉換:
-- 字符轉換
-- 轉換第一個字符
print(string.byte("Lua"))
-- 轉換第三個字符
print(string.byte("Lua",3))
-- 轉換末尾第一個字符
print(string.byte("Lua",-1))
-- 第二個字符
print(string.byte("Lua",2))
-- 轉換末尾第二個字符
print(string.byte("Lua",-2))
-- 整數 ASCII 碼轉換爲字符
print(string.char(97))
76
97
97
117
117
a
匹配模式
Lua 中的匹配模式直接用常規的字符串來描述。 它用於模式匹配函數 string.find, string.gmatch, string.gsub, string.match。
你還可以在模式串中使用字符類。
字符類指可以匹配一個特定字符集合內任何字符的模式項。比如,字符類 %d 匹配任意數字。所以你可以使用模式串 %d%d/%d%d/%d%d%d%d 搜索 dd/mm/yyyy 格式的日期:
s = "Deadline is 30/05/1999, firm"
date = "%d%d/%d%d/%d%d%d%d"
print(string.sub(s, string.find(s, date))) --> 30/05/1999
Lua 數組
數組,就是相同數據類型的元素按一定順序排列的集合,可以是一維數組和多維數組。
Lua 數組的索引鍵值可以使用整數表示,數組的大小不是固定的。
array = {"Lua", "Tutorial"}
for i= 0, 2 do
print(array[i])
end
nil
Lua
Tutorial
正如你所看到的,我們可以使用整數索引來訪問數組元素,如果知道的索引沒有值則返回nil。
在 Lua 索引值是以 1 爲起始,但你也可以指定 0 開始。
除此外我們還可以以負數爲數組索引值:
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
多維數組即數組中包含數組或一維數組的索引鍵對應一個數組。
以下是一個三行三列的陣列多維數組:
-- 初始化數組
array = {}
for i=1,3 do
array[i] = {}
for j=1,3 do
array[i][j] = i*j
end
end
-- 訪問數組
for i=1,3 do
for j=1,3 do
print(array[i][j])
end
end
1
2
3
2
4
6
3
6
9
Lua table(表)
table 是 Lua 的一種數據結構用來幫助我們創建不同的數據類型,如:數組、字典等。
Lua table 使用關聯型數組,你可以用任意類型的值來作數組的索引,但這個值不能是 nil。
Lua table 是不固定大小的,你可以根據自己需要進行擴容。
Lua也是通過table來解決模塊(module)、包(package)和對象(Object)的。 例如string.format表示使用"format"來索引table string。
table(表)的構造
構造器是創建和初始化表的表達式。表是Lua特有的功能強大的東西。最簡單的構造函數是{},用來創建一個空表。可以直接初始化數組:
-- 初始化表
mytable = {}
-- 指定值
mytable[1]= "Lua"
-- 移除引用
mytable = nil
-- lua 垃圾回收會釋放內存
當我們爲 table a 並設置元素,然後將 a 賦值給 b,則 a 與 b 都指向同一個內存。如果 a 設置爲 nil ,則 b 同樣能訪問 table 的元素。如果沒有指定的變量指向a,Lua的垃圾回收機制會清理相對應的內存。
以下實例演示了以上的描述情況:
-- 簡單的 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
able 操作
以下列出了 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進行升序排序。 |
--表的連接
fruits = {"banana","orange","apple"}
-- 返回 table 連接後的字符串
print("連接後的字符串 ",table.concat(fruits))
-- 指定連接字符
print("連接後的字符串 ",table.concat(fruits,", "))
-- 指定索引來連接 table
print("連接後的字符串 ",table.concat(fruits,", ", 2,3))
--表的移除
fruits = {"banana","orange","apple"}
-- 在末尾插入
table.insert(fruits,"mango")
print("索引爲 4 的元素爲 ",fruits[4])
-- 在索引爲 2 的鍵處插入
table.insert(fruits,2,"grapes")
print("索引爲 2 的元素爲 ",fruits[2])
print("最後一個元素爲 ",fruits[5])
table.remove(fruits)
print("移除後最後一個元素爲 ",fruits[5])
索引爲 4 的元素爲 mango
索引爲 2 的元素爲 grapes
最後一個元素爲 mango
移除後最後一個元素爲 nil
--表的排序
fruits = {"banana","orange","apple","grapes"}
print("排序前")
for k,v in ipairs(fruits) do
print(k,v)
end
table.sort(fruits)
print("排序後")
for k,v in ipairs(fruits) do
print(k,v)
end
排序前
1 banana
2 orange
3 apple
4 grapes
排序後
1 apple
2 banana
3 grapes
4 orange