前言
這篇文章將會(huì)來(lái)一些比較輕松的內(nèi)容,就是簡(jiǎn)單的介紹一下Lua中幾個(gè)常用的庫(kù)。簡(jiǎn)單的說(shuō)就是幾個(gè)API的介紹。所以說(shuō),看起來(lái)比較容易,也沒(méi)有多大的分量。就是純粹的總結(jié)。使用庫(kù)就是為了方便我們的開(kāi)發(fā),提高開(kāi)發(fā)效率,同時(shí)也能保證代碼的質(zhì)量。希望大家以后也不要重復(fù)造輪子了。
數(shù)學(xué)庫(kù)
數(shù)學(xué)庫(kù)(math)由一組標(biāo)準(zhǔn)的數(shù)學(xué)函數(shù)構(gòu)成。這里主要介紹幾個(gè)常用的函數(shù),其它的大家可以自行百度解決。
三角函數(shù)(sin,cos,tan……)
所有的三角函數(shù)都使用弧度單位,可以用函數(shù)deg(角度)和rad(弧度)來(lái)轉(zhuǎn)換角度和弧度。示例代碼:
print(math.sin(math.rad(30))) -- 0.5
謹(jǐn)記:三角函數(shù)的參數(shù)都是弧度,在實(shí)際使用中不要忘了,是弧度。
取整函數(shù)(floor,ceil)
floor:返回不大于x的最大整數(shù);向下取整;
ceil:返回不小于x的最大整數(shù);向上取整。示例代碼:
print(math.floor(5.6)) -- 5
print(math.ceil(5.6)) -- 6
最大值和最小值(max,min)
max:取參數(shù)中的最大值;
min:取參數(shù)中的最小值。示例代碼:
print(math.max(2, 3, 2, 14, 2, 30, -3)) -- 30
print(math.min(2, 3, 2, 14, 2, 30, -3)) -- -3
生成偽隨機(jī)數(shù)的函數(shù)(random,randomseed)
在實(shí)際開(kāi)發(fā)中,生成隨機(jī)數(shù)的需求是經(jīng)常有的。使用random和randomseed這兩個(gè)函數(shù)就可以輕易的完成。math.random用于生成偽隨機(jī)數(shù),可以用3種方式來(lái)調(diào)用它:
(1)如果在調(diào)用時(shí)不提供任何參數(shù),它將返回一個(gè)在區(qū)間[0, 1)內(nèi)均勻分布的偽隨機(jī)實(shí)數(shù);
(2)如果提供了一個(gè)整數(shù)n作為參數(shù),它將返回一個(gè)在區(qū)間[1, n]內(nèi)的偽隨機(jī)整數(shù);
(3)如果提供了兩個(gè)整數(shù)參數(shù)m和n,它將返回一個(gè)在區(qū)間[m, n]內(nèi)的偽隨機(jī)整數(shù)。
示例代碼如下:
print(math.random()) -- 輸出一個(gè)大于等于0,小于1的值
print(math.random(2)) -- 輸出不是1就是2
print(math.random(3, 4)) -- 輸出不是3就是4
如果你按照上面的代碼運(yùn)行,然后再看著我寫(xiě)的注釋?zhuān)憧赡芫鸵R我了,什么破注釋了,明顯就是錯(cuò)的么?每次運(yùn)行的輸出結(jié)果都是一樣的。是的,結(jié)果是一樣的,這就要說(shuō)到即將出場(chǎng)的math.randomseed。函數(shù)math.randomseed用于設(shè)置偽隨機(jī)數(shù)生成器的種子數(shù)。(看到這里,我姑且認(rèn)為你是已經(jīng)有過(guò)一年編程經(jīng)驗(yàn)的人員了,所以,你就不要問(wèn)我什么是種子了,這種概念性的東西,我想百度百科或者維基百科比我更有指導(dǎo)意義)math.randomseed的唯一參數(shù)就是一個(gè)我們稱(chēng)為種子數(shù)的值。一般我們的做法是在一個(gè)程序啟動(dòng)時(shí),用一個(gè)固定的種子數(shù)來(lái)調(diào)用它,以此初始化偽隨機(jī)數(shù)生成器。那么如何設(shè)置這個(gè)math.randomseed的種子值呢?如果使用同一個(gè)種子值的話,每次得到的隨機(jī)數(shù)就會(huì)是一樣的,在實(shí)際開(kāi)發(fā)中,一般都是使用當(dāng)前時(shí)間作為種子值,比如:
math.randomseed(os.time())
這樣就好了。一般在我們的程序啟動(dòng)時(shí),初始化一次種子就足夠了。我曾經(jīng)傻傻的在一個(gè)循環(huán)中,使用math.random取隨機(jī)數(shù),每次都調(diào)用math.randomseed(os.time())設(shè)置種子值(為什么不可以?你可以自己試一試,看看結(jié)果。如果不懂,留下你的迷惑,我們繼續(xù)交流)。
math.randomseed(os.time())
print(math.random()) -- 輸出一個(gè)大于等于0,小于1的值
print(math.random(2)) -- 輸出不是1就是2
print(math.random(3, 4)) -- 輸出不是3就是4
這樣就好了,運(yùn)行一下,看看結(jié)果吧。
table庫(kù)
table庫(kù)是由一些輔助函數(shù)構(gòu)成的,這些函數(shù)將table作為數(shù)組來(lái)操作(重點(diǎn):作為數(shù)組來(lái)操作的)。
插入和刪除函數(shù)
table.insert用于將一個(gè)元素插入到一個(gè)數(shù)組的指定位置,它會(huì)移動(dòng)后續(xù)元素以空出空間。如果在調(diào)用table.insert時(shí)沒(méi)有指定位置參數(shù),則會(huì)將元素添加到數(shù)組末尾。示例代碼:
local tb = {10, 20, 30}
table.insert(tb, 40) -- 在table的最后插入,結(jié)果為:{10, 20, 30, 40}
table.insert(tb, 2, 15) -- 在table的位置2插入,結(jié)果為:{10, 15, 20, 30, 40}
函數(shù)table.remove會(huì)刪除并返回?cái)?shù)組指定位置上的元素,并將該位置之后的所有元素前移,以填補(bǔ)空缺。如果在調(diào)用這個(gè)函數(shù)時(shí)不指定位置參數(shù),它就會(huì)刪除數(shù)組的最后一個(gè)元素。示例代碼:
local tb = {10, 20, 30}
print(table.remove(tb)) -- 刪除最后一個(gè)元素,并返回30;最后,tb = {10, 20}
print(table.remove(tb, 1)) -- 刪除第一個(gè)元素并返回10;最后,tb = {20}
現(xiàn)在有了這兩個(gè)操作,實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)中的堆棧那就輕而易舉了。等什么?自己試一試吧。
排序
對(duì)數(shù)組進(jìn)行排序,這種需求,在實(shí)際開(kāi)發(fā)中那是100%會(huì)遇到的。所以了,不會(huì)使用Lua對(duì)數(shù)組進(jìn)行排序,那是會(huì)被別人笑掉大牙的。廢話少說(shuō)。在Lua中,我們可以用table.sort完成這個(gè)任務(wù)。它可以對(duì)一個(gè)數(shù)組進(jìn)行排序,還可以指定一個(gè)可選的次序函數(shù)。這個(gè)次序函數(shù)有兩個(gè)參數(shù),如果希望第一個(gè)參數(shù)在排序結(jié)果中位于第二個(gè)參數(shù)值前,就應(yīng)當(dāng)返回true;如果沒(méi)有提供這個(gè)函數(shù),table.sort就使用默認(rèn)的小于操作。實(shí)例代碼:
local tb = {20, 10, 2, 3, 4, 89, 20, 33, 2, 3}
-- 默認(rèn)是升序排序
table.sort(tb)
for _, v in ipairs(tb) do
print(v)
end
print("=======")
-- 修改為降序排序
table.sort(tb, function (a, b) if a > b then return true end end)
for _, v in ipairs(tb) do
print(v)
end
但是,在實(shí)際開(kāi)發(fā)中,我們經(jīng)常犯這樣的錯(cuò)誤,總是試圖對(duì)一個(gè)table的索引進(jìn)行排序。在table中,索引是一個(gè)無(wú)序的集合。如果對(duì)它們進(jìn)行排序,則必須將它們復(fù)制到一個(gè)數(shù)組中,然后對(duì)這個(gè)數(shù)組進(jìn)行排序。這就是我為什么一開(kāi)始強(qiáng)調(diào)的,table庫(kù)是對(duì)數(shù)組進(jìn)行操作的。示例代碼:
local tb = {x = 20, z = 10, y = 30, m = 2, n = 8} -- 這是一個(gè)key無(wú)序的table
-- 如果想按照key的升序排列,下列代碼是不起作用的
table.sort(tb)
for k, v in pairs(tb) do
print(k .. " = " .. v)
end
正確做法是將這個(gè)table的所有key放入到一個(gè)數(shù)組中,對(duì)這個(gè)數(shù)組進(jìn)行排序。示例代碼:
local tb = {x = 20, z = 10, y = 30, m = 2, n = 8} -- 這是一個(gè)key無(wú)序的table
local keyTb = {}
for k, _ in pairs(tb) do
keyTb[#keyTb + 1] = k
end
table.sort(keyTb)
for _, v in ipairs(keyTb) do
print(v .. " = " .. tb[v])
end
現(xiàn)在就是按照key的升序排列了。
連接
使用table.concat可以完成數(shù)組的連接。它接受一個(gè)字符串?dāng)?shù)組,并返回這些字符串連接后的結(jié)果,它有一個(gè)可選參數(shù),用于指定插到字符串之間的分隔符,同時(shí)這個(gè)函數(shù)另外還接受兩個(gè)可選參數(shù),用于指定第一個(gè)和最后一個(gè)要連接的字符串索引。示例代碼:
local tb = {"Jelly", "Think", "Is", "Good"}
local strTb = table.concat(tb, " ")
print(strTb)
字符串庫(kù)
重點(diǎn)來(lái)了,學(xué)習(xí)每種語(yǔ)言,在實(shí)際工作時(shí),我們總是在和字符串進(jìn)行打交道。Lua也不例外,在Lua中真正的字符串操作能力來(lái)源于字符串庫(kù),字符串庫(kù)中的所有函數(shù)都導(dǎo)出在模塊string中?,F(xiàn)在就來(lái)對(duì)string庫(kù)進(jìn)行總結(jié)。
基礎(chǔ)字符串函數(shù)
直接通過(guò)代碼來(lái)說(shuō)吧,示例代碼:
local str = "Jelly Think"
-- string.len可以獲得字符串的長(zhǎng)度
local len = string.len(str)
print(len) -- 11
-- string.rep返回字符串重復(fù)n次的結(jié)果
str = "ab"
local newStr = string.rep(str, 2) -- 重復(fù)兩次
print(newStr) -- abab
-- string.lower將字符串小寫(xiě)變成大寫(xiě)形式,并返回一個(gè)改變以后的副本
str = "Jelly Think"
newStr = string.lower(str)
print(newStr) -- jelly think
-- string.upper將字符串大寫(xiě)變成小寫(xiě)形式,并返回一個(gè)改變以后的副本
newStr = string.upper(str)
print(newStr) -- JELLY THINK
這里重點(diǎn)介紹一下string.sub(s, i, j)函數(shù),它可以從字符串s中提取第i個(gè)到第j個(gè)字符。在Lua中,字符串的第一個(gè)字符的索引是1,但是,索引也可以是負(fù)數(shù),表示從字符串的尾部開(kāi)始計(jì)數(shù),索引-1代表字符串的最后一個(gè)字符,以此類(lèi)推。
local str = "[Jelly Think]"
local newStr = string.sub(str, 2, -2)
print(newStr) -- Jelly Think
newStr = string.sub(str, 2, 6)
print(newStr) -- Jelly
(重點(diǎn):在Lua中,字符串和其它語(yǔ)言的一樣,是不可變的,以上的操作,都會(huì)返回一個(gè)新的值,但并不會(huì)修改原來(lái)的字符串。謹(jǐn)記,謹(jǐn)記?。。。?br />
函數(shù)string.char和函數(shù)string.byte用于轉(zhuǎn)換字符及其內(nèi)部數(shù)值表示;string.char函數(shù)接受零個(gè)或多個(gè)整數(shù),并將每個(gè)整數(shù)轉(zhuǎn)換成對(duì)應(yīng)的字符,然后返回一個(gè)由這些字符連接而成的字符串。string.byte(s, i)返回字符串s中第i個(gè)字符的內(nèi)部數(shù)值表示,它的第二個(gè)參數(shù)是可選的,調(diào)用string.byte(s)可返回字符串s中第一個(gè)字符的內(nèi)部數(shù)值表示。示例代碼:
print(string.char(97)) -- a
local i = 98
print(string.char(i, i + 1, i + 2)) -- bcd
print(string.byte("abc")) -- 97
print(string.byte("abc", 2)) -- 98
print(string.byte("abc", 2, 3)) -- 98 99
print(string.byte("abc", -1)) -- 99
在Lua中也有一個(gè)神奇的函數(shù),string.format。和C語(yǔ)言中的printf是一致的。之所以說(shuō)它神奇,因?yàn)樗玫奶嗔?,也太好用了。以至于我這里就不多廢話了,我相信你們都會(huì)的。
模式匹配
由于模式匹配的東西比較多,所以,準(zhǔn)備單獨(dú)寫(xiě)篇博文單獨(dú)總結(jié)。
I/O庫(kù)
I/O庫(kù)為文件操作提供了兩種不同的模型,簡(jiǎn)單模型和完整模型。簡(jiǎn)單模型假設(shè)有一個(gè)當(dāng)前輸入文件和一個(gè)當(dāng)前輸出文件,它的I/O操作均作用于這些文件。完整模型則使用顯式地文件句柄。它采用了面向?qū)ο蟮娘L(fēng)格,并將所有的操作定義為文件句柄上的方法。
簡(jiǎn)單I/O模型
簡(jiǎn)單模型的所有操作都作用于兩個(gè)當(dāng)前文件。I/O庫(kù)將當(dāng)前輸入文件初始化為進(jìn)程標(biāo)準(zhǔn)輸入(stdin),將當(dāng)前輸出文件初始化為進(jìn)程標(biāo)準(zhǔn)輸出。在執(zhí)行io.read()操作時(shí),就會(huì)從標(biāo)準(zhǔn)輸入中讀取一行。
用函數(shù)io.input和io.output可以改變這兩個(gè)當(dāng)前文件。io.input(filename)調(diào)用會(huì)以只讀模式打開(kāi)指定的文件,并將其設(shè)定為當(dāng)前輸入文件;除非再次調(diào)用io.input,否則所有的輸入都將來(lái)源于這個(gè)文件;在輸出方面,io.output也可以完成類(lèi)似的工作。說(shuō)完了input和output,在來(lái)聊聊io.write和io.read。
io.write接受任意數(shù)量的字符串參數(shù),并將它們寫(xiě)入當(dāng)前輸出文件;它也可以接受數(shù)字參數(shù),數(shù)字參數(shù)會(huì)根據(jù)常規(guī)的轉(zhuǎn)換規(guī)則轉(zhuǎn)換為字符串。如果希望有更多的控制,可以使用string.format進(jìn)行控制。函數(shù)io.read從當(dāng)前輸入文件中讀取字符串,它的參數(shù)決定了要讀取的數(shù)據(jù):
“*all” |
讀取整個(gè)文件 |
“*line” |
讀取下一行 |
“*number” |
讀取一個(gè)數(shù)字 |
<num> |
讀取一個(gè)不超過(guò)<num>個(gè)字符的字符串 |
直接看一段示例代碼吧:
-- 先建立input.txt和output.txt兩個(gè)文件
-- 在input.txt文件中寫(xiě)入以下內(nèi)容:
--[[
//m.ythuaji.com.cn
果凍想 | 一個(gè)原創(chuàng)文章分享網(wǎng)站
88
--]]
io.input("input.txt") -- 從input.txt文件中讀取
io.output("output.txt") -- 寫(xiě)入到output.txt文件
-- 向input.txt寫(xiě)入一些測(cè)試數(shù)據(jù)
io.write("JellyThink", "\n")
io.write("果凍想", "\n")
io.write("//m.ythuaji.com.cn", "\n")
io.write(88)
讀取一整個(gè)文件的示例代碼:
str = io.read("*all") -- 讀取所有
--[[
print(str)
//m.ythuaji.com.cn
果凍想 | 一個(gè)原創(chuàng)文章分享網(wǎng)站
88
--]]
print(str)
每次讀取一行的示例代碼:
-- 用來(lái)判斷是否已經(jīng)讀到了文件末尾
-- 如果已經(jīng)到了末尾,就返回nil;否則返回空字符串
local mark = io.read(0)
while mark do
print(io.read("*line"))
mark = io.read(0)
if not mark then
print("File end.")
break
end
end
完整I/O模型
簡(jiǎn)單I/O功能太受限了,以至于基本沒(méi)有什么用處,而用的更多的則是這里說(shuō)的完整I/O模型。完整I/O模型可以進(jìn)行更多的I/O控制,它是基于文件句柄的,就好比與C語(yǔ)言中的FILE*,表示一個(gè)正在操作的文件。
要打開(kāi)一個(gè)文件,可以使用io.open函數(shù),它有兩個(gè)參數(shù),一個(gè)表示要打開(kāi)的文件名,另一個(gè)表示操作的模式字符串。模式字符串可以有以下四種取值方式:
(1)”r”:以讀取方式打開(kāi)文件;只能對(duì)文件進(jìn)行讀取操作;
(2)”w”:以寫(xiě)入方式打開(kāi)文件;可以對(duì)文件進(jìn)行寫(xiě)入操作,但是會(huì)覆蓋文件原有內(nèi)容;
(3)”a”:以追加方式打開(kāi)文件;可以對(duì)文件進(jìn)行寫(xiě)入操作;會(huì)在原來(lái)文件的基礎(chǔ)在,進(jìn)行追加寫(xiě)入;
(4)”b”:表示打開(kāi)二進(jìn)制文件,這種模式一般都是和前面三種混合使用,比如:”rb”,”wb”。
open函數(shù)會(huì)返回表示文件的一個(gè)句柄;如果發(fā)生錯(cuò)誤,就返回nil,一條錯(cuò)誤消息和一個(gè)錯(cuò)誤代碼。示例代碼:
-- 訪問(wèn)一個(gè)不存在的文件
print(io.open("ooxx.txt", r))
--[[
輸出以下內(nèi)容:
nil ooxx.txt: No such file or directory 2
--]]
當(dāng)成功打開(kāi)一個(gè)文件以后,就可以使用read/write方法讀寫(xiě)文件了,這與read/write函數(shù)相似,但是需要用冒號(hào)語(yǔ)法,將它們作為文件句柄的方法來(lái)調(diào)用,示例代碼:
local hFile = io.open("input.txt", r)
if hFile then
local strContent = hFile:read("*all")
--local strContent = hFile.read(hFile, "*all") 你也可以使用這種方法
print(strContent)
end
我們也可以將完整I/O模式與簡(jiǎn)單I/O模式混合使用。通過(guò)不指定參數(shù)調(diào)用io.input(),可以得到當(dāng)前輸入文件的句柄;而通過(guò)io.input(handle),可以設(shè)置當(dāng)前輸入文件的句柄,比如,需要臨時(shí)改變當(dāng)前輸入文件,可以這樣做:
-- io.input()不傳入?yún)?shù)時(shí),獲取當(dāng)前的輸入文件句柄
local hCurrent = io.input()
-- 打開(kāi)一個(gè)新的文件
io.input("input.txt")
-- 在新的文件上進(jìn)行操作
local strContent = io.read("*all")
print(strContent)
-- 關(guān)閉當(dāng)前文件
io.input():close()
-- 操作完成以后,恢復(fù)到以前的狀態(tài)
io.input(hCurrent)
其它文件操作
函數(shù)tmpfile返回一個(gè)臨時(shí)文件的句柄,這個(gè)句柄是以讀/寫(xiě)方式打開(kāi);這個(gè)文件會(huì)在程序結(jié)束時(shí)自動(dòng)刪除。我們?cè)谑褂脮r(shí),可以直接io.tmpfile()就ok了。
函數(shù)flush會(huì)將緩沖區(qū)中數(shù)據(jù)寫(xiě)入文件,它與write函數(shù)一樣,將其作為一個(gè)函數(shù)調(diào)用時(shí),io.flush()會(huì)刷新當(dāng)前輸出文件;而將其作為一個(gè)方法調(diào)用時(shí),f:flush()會(huì)刷新某個(gè)特定的文件f。
函數(shù)seek可以獲取和設(shè)置一個(gè)文件的當(dāng)前位置。它的一般形式是f:seek(whence, offset),其參數(shù)的具體含義如下:
(1)whence取值set,offset表示為相對(duì)于文件起始的偏移量;
(2)whence取值cur,offset表示為相對(duì)于當(dāng)前位置的偏移量;
(3)whence取值end,offset表示為相對(duì)于文件末尾的偏移量。
函數(shù)的返回值與whence無(wú)關(guān),它總是返回文件的當(dāng)前位置,即相對(duì)于文件起始處的偏移字節(jié)數(shù)。根據(jù)上述的描述,來(lái)一小段示例代碼:
function GetFileSize(hFile)
local currentPos = hFile:seek() -- 獲取當(dāng)前位置
local size = file:seek("end") -- 獲取文件大小
file:seek("set", currentPos)
return size
end
操作系統(tǒng)函數(shù)
操作系統(tǒng)庫(kù)定義在table os中,其中包含了文件操作函數(shù)、獲取當(dāng)前日期和時(shí)間的函數(shù)。為了保證Lua的可移植性,所以對(duì)于文件庫(kù)來(lái)說(shuō),就比較簡(jiǎn)單,它只包含兩個(gè)函數(shù):
用于文件改名的os.rename函數(shù);
用于刪除文件的os.remove函數(shù)。
但是對(duì)于獲取日期和時(shí)間的函數(shù),還是有必要花費(fèi)一點(diǎn)時(shí)間總結(jié)一下的。
日期與時(shí)間
在Lua庫(kù)中提供了兩個(gè)非常重要的日期和時(shí)間函數(shù),分別是time和date。那就先從time函數(shù)開(kāi)始。
time
如果不帶任何參數(shù)調(diào)用time函數(shù),它會(huì)以數(shù)字形式返回當(dāng)前的日期和時(shí)間。返回的數(shù)值表示當(dāng)前時(shí)間到某個(gè)特定時(shí)間的秒數(shù),在不同的系統(tǒng)上,這個(gè)特定的時(shí)間是不一樣的。如果用一個(gè)table作為參數(shù)調(diào)用它,它會(huì)返回一個(gè)數(shù)字,表示該table中所描述的日期和時(shí)間。這種table具有以下有效字段:
year |
一個(gè)完整的年份 |
month |
01-12 |
day |
01-31 |
hour |
00-23 |
min |
00-59 |
sec |
00-59 |
isdst |
一個(gè)布爾值,true表示夏令時(shí) |
前三個(gè)字段是必須要有的,比如:
print(os.time()) -- 輸出當(dāng)前時(shí)間的描述
print(os.time({year=2014,month=8,day=14}))
date
函數(shù)date是time的一個(gè)反函數(shù),它可以將一個(gè)表示日期和時(shí)間的數(shù)字轉(zhuǎn)換成某些高級(jí)的表現(xiàn)形式。其第一個(gè)參數(shù)是格式字符串,指定了期望的表示形式;第二個(gè)參數(shù)是日期和時(shí)間的數(shù)字,默認(rèn)為當(dāng)前日期和時(shí)間。例如:
local tbCurrentTime = os.date("*t")
for k, v in pairs(tbCurrentTime) do
print(k .. "=" .. tostring(v))
end
這樣就會(huì)輸出當(dāng)天的時(shí)間,你運(yùn)行以下代碼看看。其實(shí)data函數(shù)沒(méi)有多少需要說(shuō)的。只是data函數(shù)的第一個(gè)參數(shù)的格式種類(lèi)是非常多的,可以去百度一下。我一般用一個(gè)*t就夠了。但是了解一下其它的也還不錯(cuò)。
對(duì)于這里說(shuō)到的time和date兩個(gè)函數(shù),一般time函數(shù)返回的描述不適合人去讀,我們一般都是保存這個(gè)數(shù)字,在后臺(tái)進(jìn)行處理;對(duì)于date函數(shù),它返回的內(nèi)容適合人去讀,所以,一般使用date返回的數(shù)據(jù)在UI上顯示。
總結(jié)
對(duì)于任何語(yǔ)言來(lái)說(shuō),一個(gè)標(biāo)準(zhǔn)庫(kù)都是一個(gè)非常龐大的東西,Lua也是這樣,所以這篇文章寫(xiě)的也比較長(zhǎng)。抱歉,這只是第一部分,后面還有第二部分。所以呢,大家還是將就著看吧。雖然深的東西沒(méi)有多少,但是這也是我們?nèi)腴T(mén)一門(mén)語(yǔ)言的必經(jīng)之路。少年們,努力吧。