《Lua程式設計第四版》 第一部分前8章自做練習題答案

来源:https://www.cnblogs.com/linxiaoxu/archive/2023/08/14/17628165.html
-Advertisement-
Play Games

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

-- 另外不能跳轉到函數外

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近在寫支付的東西,調試時候需要讓支付平臺能夠回調本地介面來更新支付成功的狀態。但由於開發機器沒有公網IP,所以需要使用內網穿透來讓支付平臺能夠成功訪問到本地開發機器,這樣才能更高效率的進行調試。 推薦內網穿透的文章已經很多很多,還有很多大合集的推薦,但也因為推薦的太多,也會讓人眼花繚亂,不斷嘗試不 ...
  • 在自動化測試腳本的運行過程中,webdriver操作瀏覽器的時候,對於元素的定位是有一定的超時時間,大致應該在1-3秒的樣子,如果這個時間內仍然定位不到元素,就會拋出異常,中止腳本執行。我們可以通過在腳本中設置等待的方式來避免由於網路延遲或瀏覽器卡頓導致的偶然失敗,常用的等待方式有三種: ### 一 ...
  • 剛開始收到磁碟告警的時候,懷疑是日誌級別問題,業務日誌輸出過多導致磁碟打滿。但是查看我們自己的業務日誌文件目錄,每個日誌文件內容都不是很大。 ...
  • 1. <?php //單鏈表 class node { public $id; //節點id public $name; //節點名稱 public $next; //下一節點 public function __construct($id, $name) { $this->id = $id; $t ...
  • 我在上一章《形象談JVM-第一章-認識JVM》提到的“翻譯”,其實就是我們今天所說的“編譯”的概念。 上一章原文鏈接:https://www.cnblogs.com/xingxiangtan/p/17617654.html 原文: 【 虛擬機的職責是將位元組碼翻譯成對應系統能夠識別並執行的機器碼, 比 ...
  • python 進程與線程是併發編程的兩種常見方式。進程是操作系統中的一個基本概念,表示程式在操作系統中的一次執行過程,擁有獨立的地址空間、資源、優先順序等屬性。線程是進程中的一條執行路徑,可以看做是輕量級的進程,與同一個進程中的其他線程共用相同的地址空間和資源。 ...
  • # Linux 之 shell 編程學習筆記(並不完全正確,有誤請指正) ## 概念性知識點 ### 腳本概念 >**腳本(Script),是使用一種特定的描述性語言,依據一定的格式編寫的 可執行文件** ### 運行腳本要求 >**腳本須有 ==可執行== 許可權,即 ==x== 許可權** > >* ...
  • emm,又又遇到問題啦,現有業務系統應用上線存在視窗期,不能滿足正常任務迭代上線。在非視窗期上線容易導致資料庫、mq、jsf等線程中斷,進而導致需要手動修單問題。故而通過添加優雅停機功能進行優化,令其在上線前選擇優雅停機後,會優先斷掉新流量的涌入,並預留一定時間處理現存連接,最後完全下線,可有效擴大... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...