今天我們繼續學習Lua語法基礎教程,下篇。
九、函數
9.1 初識函數
函數是指一段在一起的、可以做某一件事兒的程序,也叫做子程序。
在前面的內容中,我們已經接觸過了函數的調用,這個函數就是前面用到了很多次的print(...)。
調用函數只需要按下面的格式即可:
函數名(參數1,參數2,參數3,......)
為何要使用函數?因為很多事情都是重復性操作,我們使用函數,可以快速完成這些操作
下面我們舉一個最簡單的函數例子,這個函數沒有傳入參數、沒有返回值
它實現了一個簡單的功能,就是輸出Hello world!:
function hello()
print('Hello world!')
end
這個函數名為hello,我們可以按下面的方法進行調用(執行):
function hello()
print('Hello world!')
end
hello()
這行代碼會輸出Hello world!。
同時,在Lua中,函數也是一種變量類型,也就是說,hello實際上也是一個變量,里面存儲的是一個函數,我們可以用下面的代碼來理解:
function hello()
print('Hello world!')
end
a = hello
--把hello函數同時賦值給a變量
a()
hello()
--a和hello變量指向同一個函數
--所以執行結果和hello()相同
因為函數只是個變量,你甚至在一開始可以這樣聲明hello函數:
hello = function()
print('Hello world!')
end
hello()
下面你需要做一件簡單的事情:
- 新建一個函數變量
biu
,使其執行后會打印biubiubiu
這個字符串 - 新建一個函數變量
pong
,使其與biu
指向的函數相同
--請在此處補全代碼
--請使下面的調用可以正常打印出biubiubiu
biu()
pong()
print("biu和pong相等嗎?",biu==pong)
9.2 local變量
之前我們創建的變量,都是全局變量,這種變量在代碼運行周期從頭到尾,都不會被銷毀,而且隨處都可調用。
但是當我們代碼量增加,很多時候大量新建全局變量會導致內存激增,我們需要一種可以臨時使用、并且可以自動銷毀釋放內存資源的變量,要怎么解決呢?
我們可以使用local標志來新建臨時變量,使用local創建一個局部變量,與全局變量不同,局部變量只在被聲明的那個代碼塊內有效。
參考下面的代碼:
a = 123
function add()
local n = a+2
print(n)
end
add()
print(n)
上面的代碼中,n就是一個局部變量,它只在這個funcion中有效,并且函數運行完后會自動回收這部分的內存。
我們應該盡可能的使用局部變量,以方便lua虛擬機自動回收內存空間,同時減少資源占用提高運行速度。
下面請閱讀以下代碼,思考一下,正確的輸出結果是什么:
str = 'abc'
function connect()
local s = str..'def'
end
print(s,str)
9.3 函數參數
在前幾章的使用中,我們知道函數是可以傳入參數的,如print(123)
那么,我們如何編寫可以傳入參數的函數呢?可以按下面的模板來寫
function 函數名(參數1,參數2,...)
代碼內容
end
這里傳入的參數,等價于在函數內部新建了一個local的變量,修改這些數據不會影響外部的數據(除了后面還沒有講到的table等類型)
舉個例子,比如下面的函數,可以實現打印出兩個傳入值的和:
function add(a,b)
print(a+b)
end
add(1,2)
--會輸出3
這段代碼其實等價于:
function add()
local a = 1
local b = 2
print(a+b)
end
add()
下面問題來了,請設計一個函數p,可以按下面的調用方式來打印出物體的密度:
--補全這個函數的代碼,滿足題目要求
function p(a,b,c,m)
print()
end
--一個長方體的長寬高分別為a、b、c(單位米)
a = 1
b = 2
c = 3
--這個物體重量為m(單位克)
m = 230
--下面打印出密度
--注:密度計算公式 密度 = 質量 / 體積
p(a,b,c,m)
9.4 函數返回值
在前面的代碼中,我們實現了一個函數,輸入變量a、b,函數會自動輸出兩個數值的和。
但是一般來說,我們的需求遠遠不止這些,我們可能需要一個如下功能的函數:
執行函數,輸入兩個值,獲取這兩個值的和
如果還是按上面幾節的內容,我們只會輸出這個值,并不能把這個值傳遞給其他的變量進行后續使用,如何解決這個需求呢?
我們可以使用函數的返回值來實現這個需求,結合上面的需求,我們可以用下面的代碼實現:
function add(a,b)
return a+b
end
all = add(1,2)
--這里all的值就是3了
print(all)
這里的return表示返回一個值,并且立刻結束這個函數的運行
同時,和輸入值可以有多個一樣,返回值也可以有多個
function add(a,b)
return a+b,"ok"
end
all, result = add(1,2)
--這里all的值就是3了
--這里result的值就是string "ok"
print(all,result)
下面問題來了,請設計一個函數p,可以按下面的調用方式來返回出物體的密度,返回值為number類型:
function p(a,b,c,m)
--請補全代碼
end
--一個長方體的長寬高分別為a、b、c(單位米)
a = 1
b = 2
c = 3
--這個物體重量為m(單位克)
m = 230
--下面返回密度值
--注:密度計算公式 密度 = 質量 / 體積
result = p(a,b,c,m)
print(result)
9.5 判斷三角形合法性2(自測題)
你需要使用前面幾章的知識,來完成下面的題目
- 已知三個number類型的變量,分別代表三根木棒的長度
- 請判斷,使用這三根木棒,是否可以組成一個三角形(兩短邊之和大于第三邊)
- 請新建一個函數triangle,并可以用如下形式調用(如果可以組成,就返回true):
function triangle(a,b,c)
--請補全代碼
end
result = triangle(1,2,3)--傳入值為三邊長度,多改幾個測試下
print(result)
9.6 返回多個值(自測題)
你需要使用前面幾章的知識,來完成下面的題目
- 已知2個number類型的變量,分別代表一個長方體的長和寬
- 請計算這個長方形的周長和面積
- 請新建一個函數rectangle,并可以用如下形式調用:
function rectangle(a,b)
--補全代碼
end
area,len = rectangle(1,2)
--結果:
--面積area為2
--周長len為6
print(area,len)
十、table
10.1 認識數組
數組,使用一個變量名,存儲一系列的值
很多語言中都有數組這個概念,在Lua中,我們可以使用table(表)來實現這個功能
在Lua中,table是一個一系列元素的集合,使用大括號進行表示,其中的元素之間以逗號分隔,類似下面的代碼:
t = {1,3,8,5,4}
我們可以直接使用元素的下標,來訪問、或者對該元素進行賦值操作。
在上面的table變量t中,第一個元素的下標是1,第二個是2,以此類推。
我們可以用變量名+中括號,中括號里加上下標,來訪問或更改這個元素,如下面的例子:
t = {1,3,8,5,4}
print(t[1]) --打印1
print(t[3]) --打印8
t[2] = 99 --更改第二個元素的值
print(t[2]) --打印99
t[6] = 2 --憑空新建第六個元素并賦值
print(t[6]) --打印2
print(t[10])
--因為不存在,打印nil
以上就是table最簡單的一個例子了,就是當作數組來用(注意,一般語言中的數組基本都為不可變長度,這里的table為可變長度)
下面你需要完成:
- 新建一個table,名為cards,存入1-10十個數字
- 將第3個元素與第7個元素交換
- 將第9個元素與第2個元素交換
- 增加第11個變量,值為23
--請補全代碼
cards =
10.2 簡單table
上一節里,我們將table來表示數組,實際上,table中可以包括任意類型的數據
比如我們可以在table中放置number和string數據,類似下面的代碼:
t = {"abc",223,",..a",123123}
我們甚至能在里面放function變量
t = {
function() return 123 end,
function() print("abc") end,
function(a,b) return a+b end,
function() print("hello world") end,
}
t1
t2
t3
t4
這些table訪問每個元素的方式仍然是直接用下標,并且也能用下標來進行修改
下面你需要完成:
--請補全代碼
funcList = {
}
a,b = 1,2--提供兩個數
print("a,b值為",a,b)
print("a和b的乘積:",funcList1)
print("a和b的差:",funcList2)
print("a和相反數:",funcList3)
10.3 table下標
在前兩節,我們的table都只是一些簡單的List(列表),每個元素的下標都是自動從1排列的
實際上,Lua中,下標可以直接在聲明時進行指定,像下面這樣:
t = {6,7,8,9}
--上面和下面的代碼等價
t = {
[1] = 6,
[2] = 7,
[3] = 8,
[4] = 9,
}
--甚至你可以跳過某些下標
t = {
[1] = 6,
[3] = 7,
[5] = 8,
[7] = 9,
}
print(t[7])
--輸出9
--在聲明后賦予元素值也是可以的
t = {}--空的table
t[101] = 10
print(t[101])
--輸出10
下面你需要:
- 新建一個變量t,并按下面的格式聲明
- 下標為1的元素,值為123(number)
- 下標為13的元素,值為"abc"(string)
- 下標為666的元素,值為"666"(string)
--請補全代碼
t = {
}
print("下標為1的元素:",t[1],type(t[1]))
print("下標為13的元素:",t[13],type(t[13]))
print("下標為666的元素:",t[666],type(t[666]))
10.4 下標進階
在上一節,我們學習了如何自定義下標,其實在Lua中,下標也可以是字符串,如下面的例子
t = {
["apple"] = 10,
banana = 12,
pear = 6,
}
--使用["下標"] = 值
--和 下標 = 值
--都是正確寫法
--當第二種方式有歧義時,應該用第一種方式
--可以用下面兩種方式訪問:
print(t["apple"])
--輸出10
print(t.apple)
--輸出10
--當第二種方式有歧義時,應該用第一種方式
可見,在使用string作為下標時,table的靈活性提升了一個數量級。
string作為下標時,也可以動態賦值:
t = {} -- 空table
t["new"] = "新的值"
print(t.new)
--輸出 新的值
下面你需要完成:
- 新建table變量t
- 下標為apple的元素,值為123(number)
- 下標為banana的元素,值為"abc"(string)
- 下標為1@1的元素,值為"666"(string)
--請補全代碼
t = {
}
print("下標為apple的元素:",t["apple"],type(t["apple"]))
print("下標為banana的元素:",t["banana"],type(t["banana"]))
print("下標為1@1的元素:",t["1@1"],type(t["1@1"]))
10.5 table小測驗
下面的代碼,將會打印什么?
t = {
apple = {
price = 7.52,
weight = 2.1,
},
banana = {
price = 8.31,
weight = 1.4,
year = '2018'
},
year = '2019'
}
print(
t.price,
t.apple.price,
t.banana.weight,
t.year
)
10.6 table小測驗2
下面的代碼,將會打印什么?
t = {
{
price = 7.52,
weight = 2.1,
},
{
price = 8.31,
weight = 1.4,
year = '2018'
},
year = '2019'
}
print(
t["price"],
t[1].price,
t[2].weight,
t["year"]
)
10.7 Lua全局變量與table
在前面我們知道了,在table中,可以直接用table名[下標]或table名.string下標來訪問元素
實際上,在Lua中,所有的全局變量全部被存放在了一個大table中,這個table名為:_G
我們可以用下面的例子來示范:
n = 123--新建變量
print(n)--輸出123
print(_G.n)--輸出123
_G.abc = 1--相當于新建全局變量
print(abc)--輸出1
_G["def"] = 23--相當于新建全局變量
print(def)--輸出23
--甚至你可以像下面這樣
_G.print("hello")
_G"print"
現在,你明白為什么說萬物基于table了吧?
你需要完成下面的任務:
- 已知有一個全局變量,名為@#$
- 請新建一個變量result
- 將@#$變量里的值賦值給result
_G["@#$"] = 123
result = --請補全代碼
print("result值為",result)
10.8 table小測試3
請新建一個名為t的table,滿足以下要求
- t[10]可獲得number類型數據100
- t.num可獲得number類型數據12
- t.abc[3]可獲得string類型數據abcd
- t.a.b.c可獲得number類型數據789
--請補全代碼
t = {
}
print("t[10]可獲得number類型數據100:",t[10],type(t[10]))
print("t.num可獲得number類型數據12:",t.num,type(t.num))
print("t.abc[3]可獲得string類型數據abcd:",t.abc[3],type(t.abc[3]))
print("t.a.b.c可獲得number類型數據789:",t.a.b.c,type(t.a.b.c))
10.9 table.concat
table.concat (table [, sep [, i [, j ] ] ])
將元素是string或者number類型的table,每個元素連接起來變成字符串并返回。
可選參數sep,表示連接間隔符,默認為空。
i和j表示元素起始和結束的下標。
下面是例子:
local a = {1, 3, 5, "hello" }
print(table.concat(a))
print(table.concat(a, "|"))
-->打印的結果:
--135hello
--1|3|5|hello
請完成下面的任務:
- 已知table變量t,
- 將t中的結果全部連起來
- 間隔符使用,
- 并使用print打印出來
t = {"a","b","c","d"}
print("連接結果:")
--補全代碼
10.10 table刪減
table.insert (table, [pos ,] value)
在(數組型)表 table 的 pos 索引位置插入 value,其它元素向后移動到空的地方。pos 的默認值是表的長度加一,即默認是插在表的最后。
table.remove (table [, pos])
在表 table 中刪除索引為 pos(pos 只能是 number 型)的元素,并返回這個被刪除的元素,它后面所有元素的索引值都會減一。pos 的默認值是表的長度,即默認是刪除表的最后一個元素。
下面是例子:
local a = {1, 8} --a[1] = 1,a[2] = 8
table.insert(a, 1, 3) --在表索引為1處插入3
print(a[1], a[2], a[3])
table.insert(a, 10) --在表的最后插入10
print(a[1], a[2], a[3], a[4])
-->打印的結果:
--3 1 8
--3 1 8 10
local a = { 1, 2, 3, 4}
print(table.remove(a, 1)) --刪除速索引為1的元素
print(a[1], a[2], a[3], a[4])
print(table.remove(a)) --刪除最后一個元素
print(a[1], a[2], a[3], a[4])
-->打印的結果:
--1
--2 3 4 nil
--4
--2 3 nil nil
請完成下面的任務:
- 已知table變量t,
- 去除t中的第一個元素
- 然后這時,在t的第三個元素前,加上一個number變量,值為810
t = {1,2,3,4,5,6,7,8,9}
--補全代碼
print("第一個元素應為2:",t[1])
print("第三個元素應為810:",t[3])
十一、循環
11.1 while循環
在實際功能實現中,經常會遇到需要循環運行的代碼,比如從1到100填充table數據,我們可以直接用循環語句來實現
我們首先來學習while
這個循環語法,整體的格式如下:
while 繼續循環判斷依據 do
執行的代碼
end
下面舉一個例子,我們計算從1加到100的結果:
local result = 0
local num = 1
while num <= 100 do
result = result + num
num = num + 1
end
print(result)
上面的代碼,就是當num≤100時,result不斷地加num,并且num每次循環后自己加1
理解了上面的代碼,我們來完成下面一個簡單的任務吧:
- 已知兩個number類型的變量min和max
- 請計算從min與max之間,所有3的倍數的和
- 打印出結果
min,max = 114,514 --這個結果應為42009
result = 0--結果存放到這個變量
while 請完善 do
--補全代碼
end
print("結果:",result)
11.2 for循環
for循環在某些程度上,和while循環很相似,但是for循環可以更加簡潔地表達中間累積的量
我們首先來學習for
這個循環語法,整體的格式如下:
for 臨時變量名=開始值,結束值,步長 do
循環的代碼
end
其中,步長可以省略,默認為1
臨時變量名可以直接在代碼區域使用(但不可更改),每次循環會自動加步長值,并且在到達結束值后停止循環
下面舉一個例子,我們計算從1加到100的結果:
local result = 0
for i=1,100 do
result = result + i
end
print(result)
上面的代碼,就是當i≤100時,result不斷地加i,并且i每次循環后增加1
理解了上面的代碼,我們來完成下面一個簡單的任務吧:
- 已知兩個number類型的變量min和max
- 請計算從min與max之間,所有7的倍數的和
- 打印出結果
min,max = 114,514 --這個結果應為17955
result = 0--結果存放到這個變量
for --補全代碼
print("結果:",result)
11.3 中斷循環
前面我們學習了循環語句,有些時候循環運行到一半,我們不想再繼續運行了,怎么辦呢?
我們可以在一個循環體中使用break,來立即結束本次循環,繼續運行下面的代碼
比如像下面這樣,計算1-100相加途中,小于100的最大的和:
result = 0
for i=1,100 do
result = result + i
if result > 100 then
result = result - i
break
end
end
print(result)
可以看見,當發現和大于100后,代碼立即把result的值還原到了加上當前數字之前的狀態,并且調用break語句,立即退出了本次循環
在while中,我們也可以使用break:
result = 0
c = 1
while true do
result = result + c
if result > 100 then
result = result - c
break
end
c = c + 1
end
print(result)
我們在這里直接使用了死循環(因為while的繼續運行判斷依據始終為true),整體邏輯也和之前for的代碼一致,當發現和大于100后,代碼立即把result的值還原到了加上當前數字之前的狀態,并且調用break語句,立即退出了本次循環
現在你需要完成一項任務:
- 請求出小于變量max的13的倍數的最大值(max大于0)
- 并將結果打印出來
- 本題理論上不用循環就能實現,但是為了練習一下技巧,請用for循環來實現
max = 810 --結果應為806
result = 0
for --請補全代碼
print(result)
11.4 循環測試題1(自測題)
前面我們學習了循環語句,我們需要完成下面的任務
我們知道,print函數可以打印一行完整的輸出
那么,已知變量a,請打印出下面的結果:
(a為大于0的整數,且需要輸出a行數據,數據從1開始,每行與上一行的差為2)
1
3
5
7
9
(上面例子為當a為5的情況)
做題區域:
a = 10
--需要用print輸出要求的結果
print("輸出結果:")
for --請補全代碼
11.5 循環測試題2(自測題)
我們需要完成下面的任務
那么,已知變量a,請打印出下面的結果:
(a為大于0的整數,且需要輸出a行數據,第一行為一個,后面每行多一個)
**
(上面例子為當a為5的情況)
做題區域:
a = 10
--需要用print輸出要求的結果
print("輸出結果:")
for --請補全代碼
11.6 循環測試題3(自測題)
我們需要完成下面的任務
那么,已知變量a,請打印出下面的結果:
(a為大于0的整數,且需要輸出a行數據,按圖示規律輸出)
1
12
123
1234
12345
123456
1234567
12345678
123456789
12345678910
1234567891011
(上面例子為當a為11的情況)
做題區域:
a = 20
--需要用print輸出要求的結果
print("輸出結果:")
for --請補全代碼
11.7 循環測試題4(自測題)
- 有一只猴子,第一天摘了若干個桃子 ,當即吃了一半,但還覺得不過癮 ,就又多吃了一個。
- 第2天早上又將剩下的桃子吃掉一半,還是覺得不過癮,就又多吃了兩個。
- 以后每天早上都吃了前一天剩下的一半加天數個(例如,第5天吃了前一天剩下的一半加5個)。
- 到第n天早上再想吃的時候,就只剩下一個桃子了。
- 那么,已知變量a為最后一天的天數,請打印出第一天的桃子數。
- 如:a為5時,輸出114
做題區域:
a = 6
--需要用print輸出要求的結果
print("輸出結果:")
for --請補全代碼
十二、詳解string庫
12.1 string.sub
接下來幾節會講解string庫的各種接口
string.sub(s, i [, j])
返回字符串 s 中,從索引 i 到索引 j 之間的子字符串。
i 可以為負數,表示倒數第幾個字符。
當 j 缺省時,默認為 -1,也就是字符串 s 的最后位置。
當索引 i 在字符串 s 的位置在索引 j 的后面時,將返回一個空字符串。
下面是例子:
print(string.sub("Hello Lua", 4, 7))
print(string.sub("Hello Lua", 2))
print(string.sub("Hello Lua", 2, 1))
print(string.sub("Hello Lua", -3, -1))
-->打印的結果:
lo L
ello Lua
Lua
值得注意的是,我們可以使用冒號來簡化語法,像下面這樣:
s = "12345"
s1 = string.sub(s, 4, 7)
s2 = s:sub(4, 7)
--兩種寫法是等價關系
print(s1,s2)
請完成下面的任務:
- 已知字符串變量s,請分別打印出(每種一行):
- s從第4個字符開始,到最后的值
- s從第1個字符開始,到倒數第3個字符的值
- s從倒數第5個字符開始,到倒數第2個字符的值
s = "1919810"
--補全代碼
print()
print()
print()
12.2 string.rep
string.rep(s, n)
返回字符串 s 的 n 次拷貝。
示例代碼:
print(string.rep("abc", 3))
--輸出結果:
--abcabcabc
請完成下面的任務:
打印一行數據,數據內容為810個114514
--補全代碼
print()
12.3 string.len
string.len(s)
接收一個字符串,返回它的長度。
示例代碼:
s = "hello lua"
print(string.len(s))
--輸出結果:
9
--同時也可以使用簡便語法
print(s:len())
請完成下面的任務:
- 新建一個變量s,使數據內容為810個114514
- 并打印出字符串s的長度
s = --補全代碼
print()
12.4 大小寫轉換
string.lower(s)
接收一個字符串 s,返回一個把所有大寫字母變成小寫字母的字符串。
string.upper(s)
接收一個字符串 s,返回一個把所有小寫字母變成大寫字母的字符串。
示例代碼:
s = "hello lua"
print(string.upper(s))
print(string.lower(s))
--輸出結果:
HELLO LUA
hello lua
--同時也可以使用簡便語法
print(s:upper())
print(s:lower())
請完成下面的任務:
已知一個變量s,打印出全是大寫字母的s字符串
s = "asd8938KJjsidiajdl;(()k)"
print --補全代碼
12.5 string.format
string.format(formatstring, ...)
按照格式化參數formatstring,返回后面...內容的格式化版本。
編寫格式化字符串的規則與標準 c 語言中 printf 函數的規則基本相同:
它由常規文本和指示組成,這些指示控制了每個參數應放到格式化結果的什么位置,及如何放入它們。
一個指示由字符%加上一個字母組成,這些字母指定了如何格式化參數,例如d用于十進制數、x用于十六進制數、o用于八進制數、f用于浮點數、s用于字符串等。
示例代碼:
print(string.format("%.4f", 3.1415926)) -- 保留4位小數
print(string.format("%d %x %o", 31, 31, 31))-- 十進制數31轉換成不同進制
d,m,y = 29,7,2015
print(string.format("%s %02d/%02d/%d", "today is:", d, m, y))
--控制輸出2位數字,并在前面補0
-->輸出
-- 3.1416
-- 31 1f 37
-- today is: 29/07/2015
請完成下面的任務:
- 已知一個變量n,為number類型整數
- 打印出n:連上n值的字符串
n = 810
print --補全代碼
12.6 string的本質
這一節我們來講解字符串的本質
字符串,是用來存儲一串字符的,但是它的本質就是一串數字。如何用一串數字來代表一串字符呢?
在計算機中,每一個符號都對應著一個數字,但是在講解這個知識之前,我們了解一下補充知識:
在大多數編程語言中,我們使用0x開頭來表示這個數字是16進制的。
比如
10等價于0x0a
256等價于0xff
接下來,你需要了解,每一個符號都對應著一個數字,比如:
0對應著0x30、1對應著0x31 a對應著0x61、b對應著0x62 A對應著0x41、B對應著0x42
上面的編碼規則,我們稱之為ascii碼,具體想了解可以打開下面的網址查看:http://ascii.911cha.com/
當然,1字節最大為0xff,即256,只能存下一部分符號,大部分的中文按某些編碼,一個中文占用2或3個字節
計算機如何解析這些數據,我們不需要了解,當你知道了上面的知識后,你應該可以理解下面的描述:
字符串"apple"實際上的內容就是下面的一串數字:
0x61,0x70,0x70,0x6c,0x65
同時,lua的字符串中可以保存任何數值,即使是0x00這種不代表任何含義的數,也可以保存
補充:在其他語言中(如C),0x00代表字符串結束,但是在lua中并不是這樣。
lua的字符串每字節可以存儲任意的一字節數據。
比如下面的描述:
有一串lua字符串中的數據為:
0x01,0x02,0x30,0x00,0x44
實際人能看到的(不可見字符用?代替):
??0?D
當然,你不能說你看不見的數據就不存在,他們都完好無損地在這個字符串中
下面你需要思考一個問題:一串字符串數據如下,它的實際內容是什么(指人能看見的字符串內容,如abcd)?
0x62,0x61,0x6e,0x61,0x6e,0x61
12.7 string.char
string.char (...)
接收 0 個或更多的整數(整數范圍:0~255),返回這些整數所對應的 ASCII 碼字符組成的字符串。當參數為空時,默認是一個 0。
如果上一章節有認真學習過了的話,這段話應該是很好理解的。實質上就是把計算機認識的一串數字,變成字符串變量,并且字符串內的數據就是要存的那串數據。
示例代碼:
str1 = string.char(0x30,0x31,0x32,0x33)
str2 = string.char(0x01,0x02,0x30,0x03,0x44)
print(str1)
print(str2)
-->輸出(不可見字符用?代替)
--0123
--??0?D
請完成下面的任務:
- 已知一個字符串的每個字符在數組t中按順序排列
- 請根據t的值,打印出字符串內容(一行數據)
- 注:這個字符串存儲的不一定是可見的字符
t = {0x79,0x6F,0x75,0x20,0x61,0x72,0x65,0x20,0x72,0x69,0x67,0x68,0x74}
print("真正的字符串內容:")
--補全代碼
12.8 string.byte
string.byte(s [, i [, j ] ])
返回字符 s[i]、s[i + 1]、s[i + 2]、······、s[j] 所對應的 ASCII 碼。i 的默認值為 1,即第一個字節,j 的默認值為 i 。
這個函數功能剛好和前面的string.char相反,是提取字符串中實際的數值。
示例代碼:
str = "12345"
print(string.byte(str,2))
print(str:byte(2))--也可以這樣
print(str:byte())--不填默認是1
-->輸出(十進制數據)
--50
--50
--49
請完成下面的任務:
- 已知字符串s
- 請把s中代表的數據,全部相加,并打印出來
s = string.char(1,2,3,4,5,6,7,8,9)
print("s內數據的和是:")
--補全代碼
12.9 string.find
string.find(s, p [, init [, plain] ])
這個函數會在字符串s中,尋找匹配p字符串的數據。如果成功找到,那么會返回p字符串在s字符串中出現的開始位置和結束位置;如果沒找到,那么就返回nil。
第三個參數init默認為1,表示從第幾個字符開始匹配,當init為負數時,表示從s字符串的倒數第-init個字符處開始匹配。
第四個參數plain默認為false,當其為true時,只會把p看成一個字符串對待。
可能你會奇怪,第四個參數有什么存在的必要嗎?p不是本來就應該是個字符串嗎? 實際上,lua中的匹配默認意義是正則匹配,同時,這里的正則與其它語言也有些許不同。
由于篇幅有限,本節和下面的幾節涉及匹配內容時,均不會考慮正則的使用方法,Lua正則教程將會在最后幾節單獨詳細地列出來。
第四個參數為true時,便不會使用正則功能。
示例代碼:
--只會匹配到第一個
print(string.find("abc abc", "ab"))
-- 從索引為2的位置開始匹配字符串:ab
print(string.find("abc abc", "ab", 2))
-- 從索引為5的位置開始匹配字符串:ab
print(string.find("abc abc", "ab", -3))
-->輸出
--1 2
--5 6
--5 6
請完成下面的任務:
- 已知字符串s,里面有很多相同的字符串
- 請找出字符串s中,所有字符串awsl的位置
- 使用print打印結果,結果一行一個
- 如字符串12awslawslaw,輸出3和7
s = "12awsaslwlaawsllslllswasllalssawwlawslaw"
print("兩個awsl的位置分別是:")
--補全代碼
12.10 string.gsub
string.gsub(s, p, r [, n])
將目標字符串s中所有的子串p替換成字符串r。
可選參數n,表示限制替換次數。
返回值有兩個,第一個是被替換后的字符串,第二個是替換了多少次。
特別提示:這個函數的目標字符串s,也是支持正則的
下面是例子:
print(string.gsub("Lua Lua Lua", "Lua", "hello"))
print(string.gsub("Lua Lua Lua", "Lua", "hello", 2)) --指明第四個參數
-->打印的結果:
-- hello hello hello 3
-- hello hello Lua 2
同樣的,我們也可以使用冒號來簡化語法,像下面這樣:
s = "12345"
r = s:gsub("2","b")
print(r)
請完成下面的任務:
- 已知字符串變量s,請分別打印出(每種一行):
- 把字符串s中,前5個a,替換為b
- 把字符串s中,前3個c,替換為xxx
- 把結果打印出來,一行數據
s = "asdicagydausckfugdaflgscdabgsdbahhacbshbsd"
print("s變換前的值:",s)
--補全代碼
十三、跨文件調用
在編寫代碼時,隨著邏輯逐漸復雜,我們的代碼量也會變大。雖然有函數可以把一部分代碼邏輯封裝起來,但是所有代碼都放到一個文件里,顯然也不是個好辦法。
所以我們需要將一些代碼放到不同文件中,通過文件來區分這些代碼的功能。
比如我們有下面這個函數:
---函數功能:
-- 生成從1-max的table
-- @輸入值:table的最大值
-- @返回: table結果
-- @例子: local list = getNumberList(10)
function getNumberList(max)
local t = {}
for i=1,max do
table.insert(t,i)
end
return t
end
我們新建一個文件叫tools.lua,把這個函數放進去,現在,整個文件如下面這樣:
tools.lua
---函數功能:
-- 生成從1-max的table
-- @輸入值:table的最大值
-- @返回: table結果
-- @例子: local list = getNumberList(10)
local function getNumberList(max)
local t = {}
for i=1,max do
table.insert(t,i)
end
return t
end
--手動返回一個table,包含了上面的函數
return {
getNumberList = getNumberList,
}
現在,我們封裝的這個函數就能在其他文件里被調用了,具體代碼如下:
--引用tools.lua文件,并加載
local tool = require("tools")
local list = tool.getNumberList(12)
當調用了require接口后,Lua虛擬機會自動加載你調用的文件,執行文件的內容,然后返回你文件里return的結果。
為了更好地理解這段話,我們可以看下面兩個文件,其中run.lua是被運行的那個入口文件
test.lua
--以便一會兒返回使用的table
local temp = {}
--把全局變量a更改了
a = 1
--local變量無法被外部調用
--但是可以在文件內被調用
local b = 2
--文件在被require的時候,會被執行
--把全局變量c更改了
c = a + b
--使函數在table里
function temp.addB()
--文件內部可以調用變量b
b = b + 1
return b
end
--返回table
return temp
run.lua
local test = require("test")
print(a)--輸出1
print(b)--輸出nil,因為b是local變量
print(c)--輸出3
print(test.addB())--輸出3
print(test.addB())--輸出4
print(test.addB())--輸出5
同時,每個文件最多只會被require一次,如果有多個require,只有第一次會執行。
-
函數
+關注
關注
3文章
4308瀏覽量
62444 -
Lua
+關注
關注
0文章
80瀏覽量
10547
發布評論請先 登錄
相關推薦
評論