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