Lua程式設計第四版第一部分語言基礎自做練習題答案,帶:star:為重點。 ## 1.1 > 運行階乘的示例並觀察,如果輸入負數,程式會出現什麼問題?試著修改代碼來解決問題 輸入負數,程式會死迴圈,修改如下 ```lua -- 定義一個計算階乘的函數 function fact(n) if n 分別 ...
Lua程式設計第四版第一部分語言基礎自做練習題答案,帶⭐為重點。
1.1
運行階乘的示例並觀察,如果輸入負數,程式會出現什麼問題?試著修改代碼來解決問題
輸入負數,程式會死迴圈,修改如下
-- 定義一個計算階乘的函數
function fact(n)
if n <= 0 then
return 1
else
return n * fact(n - 1)
end
end
print("enter a number")
a = io.read("*n")
while a < 0 do
print("number is negative, enter a number")
a = io.read("*n")
end
print(fact(a))
1.2
分別使用-l參數和dofile運行twice示例,並感受你喜歡哪種方式
-l
載入庫,在lua解釋器之外運行。
lua -l lib1
dofile
讀取文件,在lua解釋器之內運行。
print("use dofile")
dofile("1.1.lua")
1.4
以下字元串中哪些是有效的標識符
___ _end End end until? nil NULL one-step
end 為關鍵字,until?帶?無關字元,nil為關鍵字,one-step中帶-無關字元,這幾個不是
1.5
表達式
type(nil)==nil
的值是什麼? 能解釋原因嗎
false,因為type函數總是返回字元串。
1.6
除了使用函數type外,如何檢查一個值是否為Boolean類型?
--a = true
a = false
--a = 1
--a = "true"
print(a == true or a == false)
1.7
考慮如下的表達式
(x and y and (not z)) or ((not y) and x)
其中的括弧是否是必須的?
不是必須的,加括弧更清晰。
1.8
請編寫一個可以列印出腳本自身名稱的程式
print(arg[0])
2.0 ⭐
八皇後問題有92解。皇後可以在橫、豎、斜線上不限步數地吃掉其他棋子。如何將8個皇後放在棋盤上(有8 * 8個方格),使它們誰也不能被吃掉!這就是著名的八皇後問題。
回溯法
N = 8 -- 棋盤大小
FuncCount = 0 --調用IsPlaceOK的次數
-- 檢查第n行第c列皇後會不會被前面已有的n-1個皇後攻擊
function IsPlaceOK(a, n, c)
for i = 1, n - 1 do
if a[i] == c or n - i == a[i] - c or n - i == c - a[i] then
return false
end
end
return true
end
-- 列印棋盤
function PrintSolution(a)
for i = 1, N do
for j = 1, N do
io.write(a[i] == j and "x" or "-", " ")
end
io.write("\n")
end
io.write("\n")
end
-- 放置從n到N的皇後,遞歸
function AddQueen(a, n)
if n > N then
PrintSolution(a)
else -- 放置第n個皇後
for c = 1, N do
ok = IsPlaceOK(a, n, c)
FuncCount = FuncCount + 1
if ok then
a[n] = c
AddQueen(a, n + 1)
end
end
end
end
AddQueen({}, 1)
print(string.format("調用IsPlaceOK的次數%d", FuncCount))
2.1
修改八皇後問題的程式,使其在輸出第一個解後即停止運行
修改列印棋盤函數,調用操作系統函數,首次列印時提前退出
os.exit()
2.2 ⭐
解決八皇後問題的另一種方式是,先生成1~8之間的所有排列,然後一次遍歷這些排列,檢查每一個排列是否是八皇後問題的有效解。請使用這種方法修改程式,並對比新程式與舊程式之間的性能差異,比較isplaceok函數的次數
全排列問題,胡凡演算法筆記第115頁。需要一個額外的表來記錄狀態。
N = 8 -- 棋盤大小
HashTable = {} -- 記錄狀態
Count = 0 -- 記錄數量
FuncCount = 0 --調用IsPlaceOK的次數
for i = 1, N do
HashTable[i] = false
end
-- 列印棋盤
function PrintSolution(a)
for i = 1, N do
for j = 1, N do
io.write(a[i] == j and "x" or "-", " ")
end
io.write("\n")
end
io.write("\n")
end
-- 檢查排列
function IsPlaceOK(a)
for i = 1, N do
for j = i + 1, N do
if a[i] == a[j] or j - i == a[i] - a[j] or j - i == a[j] - a[i] then
return
end
end
end
PrintSolution(a)
Count = Count + 1
end
-- 生成皇後
function AddQueen(a, n)
if n > N then
IsPlaceOK(a)
FuncCount = FuncCount + 1
end
for i = 1, N do
if HashTable[i] == false then
a[n] = i
HashTable[i] = true
AddQueen(a, n + 1)
HashTable[i] = false
end
end
end
AddQueen({}, 1)
print(string.format("共%d種方法", Count))
print(string.format("調用IsPlaceOK的次數%d", FuncCount))
2.0調用IsPlaceOK的次數15720,2.2調用IsPlaceOK的次數40320
3.1
以下哪些是有效的數值常量?它們的值分別是多少
.0e12 .e12 0.0e 0x12 0xABFG 0xA FFFF 0xFFFFFFFF 0x 0x1P10 0.1e1 0x0.1p1
print(0e12)
-- print(.e12)
-- print(0.0e)
print(0x12)
-- print(0xABFG)
print(0xA)
-- print(FFFF)
print(0xFFFFFFFF)
-- print(0x)
print(0x1P10)
print(0.1e1)
print(0x0.1p0)
print(0x0.Fp0)
print(0x0.1p1)
print(0x0.Fp1)
3.2
解釋下列表達式之所以得出響應結果的原因(整型算術運算總是會迴環
math.maxinteger * 2 --> -2
math.mininteger * 2 --> 0
math.maxinteger * math.maxinteger --> 1
math.mininteger * math.mininteger --> 0
print(0xFFFFFFFFFFFFFFFF) -- -1
print(0x8000000000000000) -- 最小的負整數
print(0x7FFFFFFFFFFFFFFF)
print(0x7FFFFFFFFFFFFFFF * 2) -- 迴環,對最高位取捨,等價於
print(0xFFFFFFFFFFFFFFFE)
print(0x8000000000000000 * 2) -- 迴環,對最高位取捨,等價於
print(0x0000000000000000)
-- math.maxinteger除首位外全1,相乘後得到除最後一位和首部外,中間全0,超過符號位以外的部分被拋棄,其餘全為0,最後只剩最後一位的1,所以結果為1。
-- math.mininteger除首位外全0,超出符號位以外的數值均被拋棄,其餘全為0,所以結果為0。
--[[
二進位乘法要求滿二進一原則
"_"符號為捨棄高位
求解:0x7FFFFFFFFFFFFFFF * 2
01111111 <= 0x7F
* 0010 <= 0x2
=============
00000000
01111111
=============
_11111110 => 0xFE
求解:0x8000000000000000 * 2
10000000 <= 0x80
* 0010 <= 0x2
=============
00000000
10000000
=============
_00000000 => 0x00
求解:math.maxinteger * math.maxinteger
0111
* 0111
=============
0111
0111
0111
0111
=============
_0001 => 1D
範例
1001
* 1101
=============
1001
0000
1001
+ 1001
=============
1110101
]]
3.3
下列代碼的輸出結果是什麼
for i = -10 , 10 do print(i,i%3) end
-10 2
-9 0
-8 1
-7 2
-6 0
-5 1
-4 2
-3 0
-2 1
-1 2
0 0
1 1
2 2
3 0
4 1
5 2
6 0
7 1
8 2
9 0
10 1
3.4
表達式 2 ^ 3 ^ 4的值是什麼?表達式 2 ^ -3 ^ 4 呢?
print(2 ^ 3 ^ 4)
print(2 ^ (3 ^ 4))
print((2 ^ 3) ^ 4)
print(2 ^ -3 ^ 4) -- 冪運算優先順序大於"-"
print(2 ^ (-3) ^ 4)
print(2 ^ -(3 ^ 4))
-- 2.4178516392293e+024
-- 2.4178516392293e+024
-- 4096.0
-- 4.1359030627651e-025
-- 2.4178516392293e+024
-- 4.1359030627651e-025
3.5
不懂
print(12.7 == 25.4/2)
print(12.7 == 406.4 / 2^5)
print(5.5 == 55/10)
print(5.5 == 11/2)
print(5.5 == 22/4)
print(5.5 == 176/2^5)
3.6 ⭐
請編寫一個通過高、母線與軸線夾角來計算正圓錐體體積的函數
function CalCloneVolume(r, h)
return math.pi * r ^ 2 * h / 3
end
print(CalCloneVolume(2, 3) == 12.566370614359) -- false 的原因
answer-1
You're multiplying something by pi, so the result is an irrational number which has a non-repeating fractional portion. .566370614359 is only the first 12 decimal places of a sequence that continues forever.
Internally, Lua uses a 64-bit floating point representation (on most platforms), so it only contains an approximation of that fraction, but it has a lot more precision than 12 decimal places. You'd have to understand the IEEE-754 floating point pretty intimately to predict the exact value for an equality comparison like that.
I can get true on my machine if I go out to at least 15 decimal places, but you shouldn't use floating point numbers that way.
I suspect you got 12.566370614359 by just printing the output of CalCloneVolume(2, 3). You're getting 12 decimal places there only because that's the default inside some routine in Lua that formats floating point numbers for display. You could show more decimal places like this:print(string.format("%.50g", CalCloneVolume(2, 3)))
answer-2
Generally it’s best not to compare floating point numbers for exactly equality unless you know they are storing integers. Integers (within a certain range) are stored precisely - so integer comparisons are ok.
Other real numbers (with fractional parts) are stored in binary not in decimal, which means that it’s hard to know what the exact number is - and some numbers can’t represented exactly. Irrational numbers are one example for both decimal and binary, but there are plenty of others - and they are not the same for binary and decimal.
Additionally different machines can have different bits, e g. 64 bits are common with PC, but you might want to only use 32 bits on a embedded device. Some machines use 80 bits. Additionally what they use these bit for inside a floating point number vary.
Additionally you can get problems with certain operations - divide for instance is the normal trouble maker. I notice you are dividing by 3. If you divide 1 by three you can’t represent this number exactly as with a finite number of digits on decimal or binary. (You can in ternary… base 3). In decimal it’s 0.333333333…forever and a 0.0101001010101010101… forever in binary but 0.1 in base 3. With floating point numbers you are only using a fixed number of bits.
As an example you might end up with three lots of 1/3 added together … which mathematically equals one, but in decimal representation looks like 0.99999999999 - something which confuses students today.
Comparing for higher then > or lower than < is fine. As of compare higher or equal >= or lower than equal <=.
If you need to compare for equality where you think you can get an approximate number … then you can check if it’s close to a number … for instance if x > 0.9 and x < 1.1
People get upset that some calculation ends up as 5.000000001 but floating point numbers are really cool as long as you understand their limitations.
3.7 ⭐
利用函數math.random編寫一個生成遵循正態分佈的偽隨機數發生器
其他正態分佈都可以用 0-1 正態分佈 N(0,1) 生成。由概率論知, 若 \(Y_{1}, Y_{2}, \cdots, Y_{N}\) 是 n 個獨立同分佈的隨機變數, 當 n 足夠大時 \(X=Y_{1}+Y_{2}+\cdots+Y_{n}\) 就近似於一個正態分佈.一般來說, 當 n>6 時, X 就是一個正態分佈的很好的近似. X 的均值和方差分別為
\(\begin{array}{c} \mu_{x}=\mu_{1}+\mu_{2}+\cdots+\mu_{n}=n \mu \\ \sigma_{x}^{2}=\sigma_{1}^{2}+\sigma_{2}^{2}+\cdots+\sigma_{n}^{2}=n \sigma^{2} \end{array}\)
\(\begin{array}{c} X=Y_{1}+Y_{2}+\cdots+Y_{n} \\ z=\frac{\sum_{i=1}^{n} y_{i}-n \mu}{\sqrt{n \sigma^{2}}}, \quad z \in N(0,1) \end{array}\)
令 \(Y_{i}\) 為 0-1 均勻分佈 U(0,1) , 已知 \(\mu=\frac{1}{2}, \sigma=\frac{1}{2 \sqrt{3}}\) , 代入
\(z=\frac{\sum_{i=1}^{n} y_{i}-n / 2}{\sqrt{n / 12}}\)
取 n=12 , 得 \(z=\sum_{i=1}^{12} y_{i}-6\)
給定數學期望和標準差, 計算 \(x=\mu+\sigma Z\) 便可得到服從 \(N\left(\mu, \sigma^{2}\right)\) 正態分佈的隨機數 x
-- 正態分佈隨機數發生器
function NormalDistribution(mean, std) -- 給出範圍
local z = 0
for i = 1, 12, 1 do
z = z + math.random()
end
z = z - 6
return z * std + mean
end
local count = 0
local threshold = 2.576 -- 1.645
for i = 1, 10 ^ 5, 1 do
x = NormalDistribution(0, 1)
if x < threshold and x > -threshold then
count = count + 1
end
end
print(count)
print(string.format("%.6f", count / 10 ^ 5))
4.1
請問如何在Lua程式中以字元串的方式使用如下的XML片段,請給出至少兩種實現方式
<![CDATA] Hello World ]]>
xml = [==[
<![CDATA]
Hello World
]]>]==]
print(xml)
xml2 = "\z
<![CDATA]\n\z
Hello World\n\z
]]>"
print(xml2)
xml3 = "\060\033\091CDATA\091\010Hello\032world\010\093\093\062"
print(xml3)
4.2
假設你需要以字元串常量的形式定義一組包含歧義的轉義字元序列,你會使用哪種方式?請註意考慮諸如可讀性、每行最大長度及字元串最大長度等問題。
考慮可讀性和字元串最大長度,可以使用 [==[ ... ]==]
或 \z
的形式。
如果字元串不是很多,可以用 \ddd
、\xhh
、\u{h..h}
來表示字元串。
4.3
請編寫一個函數,使之是現在某個字元串的指定位置插入另一個字元串
function insert(a, index, b)
return string.sub(a, 1, index - 1) .. b .. string.sub(a, index, -1)
end
print(insert("hello world", 1, "start: "))
print(insert("hello world", 7, "small "))
4.4
使用UTF-8字元串重寫4.3,起始位置和長度都是針對代碼點而言的
function insert(a, index, b)
index = utf8.offset(a, index)
return a:sub(1, index - 1) .. b .. a:sub(index, -1)
end
print(insert("résumé", 7, "!"))
print(insert("résumé", 6, "!"))
4.5
請編寫一個函數,該函數用於移除指定字元串中的一部分,移除的部分使用起始位置和長度指定
function remove(s, i, k)
return s:sub(1, i - 1) .. s:sub(i + k, -1)
end
print(remove("hello world", 7, 4))
4.6
使用UTF-8字元串重寫4.5,起始位置和長度都是針對代碼點而言的
function remove(s, i, k)
i = utf8.offset(s, i)
k = utf8.offset(s, i + k)
return s:sub(1, i - 1) .. s:sub(k, -1)
end
print(remove("résumé", 2, 2))
4.7
請編寫一個函數判斷指定的字元串是否為迴文字元串
function ispali(s)
for i = 1, #s // 2 do
if s:byte(i) ~= s:byte(-i) then
return false
end
end
return true
end
print(ispali("banana"))
print(ispali("step on no pets"))
5.1
下列代碼的輸出是什麼,為什麼
sunday = "monday";
monday = "sunday"
t = {
sunday = "monday",
[sunday] = monday
}
print(t.sunday, t[sunday], t[t.sunday])
-- monday sunday sunday
5.2
考慮如下代碼,a.a.a.a的值是什麼,其中每個a都一樣嗎
如果將如下代碼 a.a.a.a=3 追加到上述代碼中,現在 a.a.a.a 的值變成了什麼
a = {}
a.a = a
print(a)
print(a.a)
print(a.a.a)
print(a.a.a.a)
print(a == a.a)
print(a.a.a == a.a.a.a)
--[[
table: 00000000009e0f50
table: 00000000009e0f50
table: 00000000009e0f50
table: 00000000009e0f50
true
true
]]
a.a.a.a = 3 -- => {}.a = 3
print(a)
print(a.a)
-- print(a.a.a) -- attempt to index a number value
5.3
假設要創建一個以轉義序列為值、以轉義序列對應字元串為鍵的表,請問應該如何編寫構造器
a = {
["\007"] = "\\a",
["\008"] = "\\b",
["\009"] = "\\t",
["\010"] = "\\n",
["\011"] = "\\v",
["\012"] = "\\f",
["\013"] = "\\r",
["\\"] = "\\\\",
["\""] = "\\\"",
["\'"] = "\\'"
}
for k, v in pairs(a) do
print(k, v)
end
5.4
編寫一個函數,該函數以多項式(使用表表示)和值x為參數,返回結果為對應多項式的值
function calfunc(t, x)
local sum = 0
for i, v in ipairs(t) do
sum = sum + v * x ^ (i - 1)
end
return sum
end
t = {1, 2, 1}
print(calfunc(t, 4))
5.5
改寫5.4,使之最多使用n個加法和n個乘法,且沒有指數
function calfunc(t, x)
local sum = 0
local xb = x
if t[1] then
sum = t[1]
end
for i = 2, #t, 1 do
sum = sum + t[i] * x
x = x * xb
end
return sum
end
t = {1, 2, 1}
print(calfunc(t, 4))
5.6
請編寫一個函數,該函數用於測試指定的表是否為有效的序列
function isValidSequence(t)
for i = 1, #t, 1 do
if t[i] == nil then
return false
end
end
return true
end
print(isValidSequence({1, 2, 3, 4, 5}))
print(isValidSequence({1, 2, 3, 4, 5, nil}))
print(isValidSequence({1, 2, 3, nil, 5}))
print(isValidSequence({nil, 2, 3, 4, 5}))
-- pairs\ipairs 會跳過nil鍵值對
5.7
請編寫一個函數,該函數將指定列表的所有元素插入到另一個列表的指定位置
function moveTable(a, b, i)
table.move(b, i, #b, i + #a)
table.move(a, 1, #a, i, b)
end
a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
b = {-1, -2, -3}
moveTable(a, b, 2)
for k, v in pairs(b) do
print(k, v)
end
5.8
實現表標準庫函數 table.concat 併進行性能對比
..
多次拼接,每次創建新字元串,性能低
function concat(t)
local s = ""
for i, v in ipairs(t) do
s = s .. v
end
return s
end
print(concat({"hello", " ", "world"}))
print(table.concat({"hello", " ", "world"}))
a = {}
for i = 1, 2 ^ 19, 1 do
a[i] = 'a'
end
start = os.clock()
concat(a)
print(os.clock() - start)
start = os.clock()
table.concat(a)
print(os.clock() - start)
--[[
hello world
hello world
8.1589999999997
0.0070000000014261
]]
6.1
請編寫一個函數,該函數的參數為一個數組,列印出該數組的所有元素
function showArray(list)
for i = 1, #list, 1 do
print(list[i])
end
end
showArray({1, 2, 3, 4, 5})
6.2
請編寫一個函數,該函數的參數為可變數量的一組值,返回值為除第一個元素之外的其他所有值
function showArray(...)
local t = {}
for i, v in ipairs({...}) do
if i ~= 1 then
t[#t + 1] = v
end
end
return t
end
t = showArray(1, 2, 3, 4, 5)
print(table.unpack(t))
6.3
請編寫一個函數,該函數的參數為可變數量的一組值,返回值為除最後一個元素之外的其他所有值
function showArray(...)
local t = {}
for i, v in ipairs({...}) do
if i ~= #{...} then
t[#t + 1] = v
end
end
return t
end
t = showArray(1, 2, 3, 4, 5)
print(table.unpack(t))
6.4
請編寫一個函數,該函數用於打亂一個指定的數組。請保證所有的排列都是等概率的
-- 排列問題
function randomArray(t, index, state)
index = index or {}
state = state or {}
if #index == #t then
for i = 1, #t, 1 do
print(t[index[i]])
end
return index
end
repeat
a = math.random(1, #t)
until state[a] ~= true
state[a] = true
index[#index + 1] = a
return randomArray(t, index, state) -- 尾調用消除
end
randomArray({1, 2, 3, 4, 5})
-- for i, v in ipairs(randomArray({1, 2, 3, 4})) do
-- print(i, v)
-- end
6.5
請編寫一個函數,其參數為一個數組,返回值為數組中元素的所有組合
res = {}
tmp = {}
function showCombine(arr, x)
choose(arr, 1, 1, x)
end
-- arr-數組 n-選擇組合中第幾個 i-從第幾個索引開始取 x-需要取多少個元素
function choose(arr, n, i, x)
if (n > x) then
res[#res + 1] = {table.unpack(tmp)}
return
end
for k = i, #arr do
tmp[n] = arr[k]
choose(arr, n + 1, k + 1, x)
end
end
showCombine({1, 2, 3, 4, 5}, 3)
for i = 1, #res do
for z = 1, #res[i] do
io.write(res[i][z])
end
io.write("\n")
end
ANTI SPIDER BOT -- www.cnblogs.com/linxiaoxu
7.1
請編寫一個程式,該程式讀取一個文本文件然後將每行的內容按照字母表的順序排序後重寫該文件。如果在調用時不帶參數,則從標準輸入讀取並向標準輸出寫入;如果在調用時傳入一個文件名作為參數,則從該文件中讀取並向標準輸出寫入;如果在調用時傳入兩個文件名作為參數,則從第一個文件讀取並將結果寫入到第二個文件中。
function sortTXT(from, to)
local t = {}
from = from or ""
to = to or ""
if from ~= "" then
local f = assert(io.open(from, "r"))
for line in f:lines() do
t[#t + 1] = line
end
f:close()
else
io.input(io.stdin)
for line in io.lines() do
t[#t + 1] = line
if line == "" then
break
end
end
end
table.sort(t)
if to ~= "" then
f = assert(io.open(to, 'w'))
for _, v in ipairs(t) do
f:write(v, "\n")
end
f:close()
else
for _, v in ipairs(t) do
io.write(v, "\n")
end
end
end
-- sortTXT()
sortTXT("./test.txt")
sortTXT("./test.txt", "./test2.txt")
7.2
請改寫7.1,使得當指定的輸出文件已經存在時,要求用戶進行確認
function sortTXT(from, to)
local t = {}
from = from or ""
to = to or ""
if from ~= "" then
local f = assert(io.open(from, "r"))
for line in f:lines() do
t[#t + 1] = line
end
f:close()
else
io.input(io.stdin)
for line in io.lines() do
t[#t + 1] = line
if line == "" then
break
end
end
end
table.sort(t)
if to ~= "" then
err = io.open(to, 'r')
if err ~= nil then
err:close()
io.stdout:write("當前文件已存在,確定請輸 1\n")
ok = io.stdin:read("l")
if ok ~= "1" then
return
end
end
f = assert(io.open(to, 'w'))
for _, v in ipairs(t) do
f:write(v, "\n")
end
f:close()
else
for _, v in ipairs(t) do
io.write(v, "\n")
end
end
end
sortTXT("./test.txt", "./test2.txt")
7.3
對比使用下列幾種不同的方式把標準輸入流複製到標準輸出流中的Lua程式的性能表現
- 按位元組
- 按行
- 按塊 8KB
- 一次性讀取
io.input("./huge.txt")
start = os.clock()
for count = 1, math.huge do
s = io.read(1)
if s == nil then
break
end
io.write(s)
end
io.write(os.clock() - start)
-- 3.839 26.559
-- start = os.clock()
-- for count = 1, math.huge do
-- s = io.read('l')
-- if s == nil then
-- break
-- end
-- io.write(s)
-- end
-- io.write(os.clock() - start)
-- 0.654 4.309
-- start = os.clock()
-- for count = 1, math.huge do
-- s = io.read(2 ^ 13)
-- if s == nil then
-- break
-- end
-- io.write(s)
-- end
-- io.write(os.clock() - start)
-- 0.579 4.122
-- start = os.clock()
-- s = io.read('a')
-- io.write(s)
-- io.write(os.clock() - start)
-- 0.5969999 4.201
7.4
請編寫一個程式,該程式輸出一個文本文件的最後一行。當文件較大且可以使用seek時,請嘗試避免讀取整個文件。
function lastLine(file)
local f = io.open(file, 'r')
local current = f:seek()
local size = f:seek("end")
local tmp = ""
f:seek("set", current)
if size > 2 ^ 20 then
f:seek("set", size // 2 + size // 4 + size // 8) -- 切到 7/8 進度
end
for line in f:lines() do
tmp = line
end
io.write(tmp, "\n")
f:close()
end
lastLine("./huge.txt")
7.5
修改7.4,使其可以輸出一個文本文件的最後n行。同時,當文件較大且可以使用seek時,請嘗試避免讀取整個文件。
function lastLine(file, n)
local f = io.open(file, 'r')
local current = f:seek()
local size = f:seek("end")
local tmp = {}
f:seek("set", current)
if size > 2 ^ 20 then
f:seek("set", size // 2 + size // 4 + size // 8) -- 切到 7/8 進度
end
for line in f:lines() do
tmp[#tmp + 1] = line
end
for i = 1, n, 1 do
io.write(tmp[#tmp - n + i], "\n")
end
f:close()
end
lastLine("./huge.txt", 3)
8.2
描述Lua語言中實現無條件迴圈的4種不同方法
while true do
end
for i = 1, math.huge do
end
repeat
until nil
::s1::
do
goto s1
end
8.4
將迷宮游戲的goto語句全部修改為尾調用消除形式
function room1()
local move = io.read()
if move == "south" then
return room3()
elseif move == "east" then
return room2()
else
print("invalid move")
return room1()
end
end
function room2()
local move = io.read()
if move == "south" then
return room4()
elseif move == "west" then
return room1()
else
print("invalid move")
return room2()
end
end
function room3()
local move = io.read()
if move == "north" then
return room4()
elseif move == "east" then
return room1()
else
print("invalid move")
return room3()
end
end
function room4()
print("Congratulations, you won!")
end
room1()
8.5
解釋一下為什麼Lua語言會限制goto語句不能跳出一個函數
不同函數之間如果能使用goto跳轉會導致代碼可讀性變差,不利於維護,其次,直接跳轉到某個變數的作用域,卻繞過了變數的聲明將會發生無法預料的錯誤
goto
print(1919180)
-- goto bb
do
local x = 1
goto bb
::cc:: -- 不能跳轉到局部變數作用域
x = 3
print(x)
::dd:: -- 可以跳轉到這,局部變數作用域終止於聲明變數的代碼塊中的最後一個有效語句
end
::bb::
do
::aa:: -- 可見性原則
print("114514")
end
-- goto aa
-- 另外不能跳轉到函數外