十分鐘學會Lua三:程式設計技巧之閉包與模式匹配
三:程式設計技巧
1、 閉包:
簡單來說,一個閉包就是一個函式外加能夠使該函式正確地訪問非區域性變數所需的其他機制。
介紹一個閉包應用的場景:當重新定義一個函式時,我們需要在新的實現中呼叫原來的那個函式。例如,假如要重新定義函式sin一使其引數以角度為單位而不是以弧度為單位。那麼這個新函式可以先對引數進行轉換,再呼叫原來的sin函式進行真正的計算。
do
local oldSin = math.sin
local k = math.pi/180
math.sin = function(x)
return oldSin(k*x)
end
end
上述程式碼使用了do程式碼來限制區域性變數oldSin地作用範圍。我們可以使用同樣的技巧來建立安全地執行時環境,即所謂的沙盒。
(1):在Lua語言中,函式是嚴格遵守詞法定界的第一類值。“第一類值“意味著Lua語言中的函式與其他常見型別的值(例如數值和字串)具有同等許可權。”詞法定界“意味著Lua語言中的函式可以訪問包含其自身的外部函式中的變數。
(2):高階函式:舉例說明,
table.sort(table1,function (a,b) return (a.name>b.name) end)
該以另一個函式作為引數的函式被稱為高階函式,其實現基於匿名函式的機制:函式定義實際上是建立型別為“function“的值並把它賦值給一個變數的語句,即函式是沒有名字的,即匿名(anonymous)。
(3):非全域性函式:函式不僅可以被儲存在全域性變數中,還可以被儲存在表字段和區域性變數中。其中,儲存在表字段中是Lua實現面向物件的程式設計的關鍵要素。舉例說明,
local fact
fact=function (n)
if n==0 then return 1
else return n*fact(n-1)
end
end
該程式段是一個區域性的巢狀函式。
(4):詞法定界:當編寫一個被其他函式B包含的函式A時,被包含的函式A可以訪問包含其地函式B的所有區域性變數,我們將這種特性稱為詞法定界。
(5):函數語言程式設計:以開發一個表示幾何區域的簡單系統為例。
定義一個根據指定的圓心和半徑建立的圓盤:
function disk (cx,cy,r)
return function (x,y)
return (x-cx)^2 + (y-cy)^2 <= r^2
end
end
定義一個指定邊界的軸對稱矩陣:
function rect (left,right,bottom,up)
return function (x,y)
return left <= x and x <=right and
bottom <=y and y<=up
end
end
2、 模式匹配:
(1) 模式:Lua語言中的模式使用百分號%作為轉義符。
下列列出了所有預置的字元分類和其含義:
. |
任意字元 |
%a |
字母 |
%c |
控制字元 |
%d |
數字 |
%g |
除空格外的可列印字元 |
%l |
小寫字元 |
%p |
標點符號 |
%s |
空白字元 |
%u |
大寫字元 |
%w |
字母和數字 |
還可以通過描述模式中重複和可選部分的修飾符(modifier)來讓模式更加有用。
+ |
重複一次或多次 |
* |
重複零次或多次 |
- |
重複零次或多次(最小匹配) |
? |
可選(出現零次或一次) |
(2)字串標準庫提供了基於模式的4個函式,分別是:string.find,string.match,string.gsub,string.gmatch
string.find:參照如下程式碼段
s = “hello achevery,how are you”
i.j=string.find(s,”hello”)
print(i,j) --》 1 5
string.match:參照如下程式碼段
data=”Today is 2021/9/27”
d=string.match(data,”%d+/%d+/%d+”)
print(d) --》 2021/9/27
其中,“%d+“表示一個非空的數字序列,類似的,模式”%a+“表示一個非空的字母序列,”%s*“表示一個可能為空的空白序列。
string.match具有捕獲模式,即將所有捕獲到的值作為單獨的結果返回,可以通過把模式中需要捕獲的部分放到一對圓括號內來指定捕獲。如:
pair = “ name =achevery”
key,value=string.match(pair,”(%a+)%s*=%s*(%a+)”)
print(key, value) --》 name Anna
string.gsub:該函式有三個必選引數,目標字串、模式和替換字串,其基本用法是將目標字串中所有出現模式的地方替換成替換字串。如:
s=string.gsub(“achevery is cute”, “cute”, “great”)
print(s) --》 achevery is cute
函式string.gsub的第三個引數不僅可以是字串,還可以是一個函式或表。
當第三個引數是一個函式時,函式string.gsub會在每次找到匹配時呼叫該函式,引數是捕獲到的內容而返回值則被作為替換字串。當第三個引數是一個表時,函式會把第一個捕獲到的內容作為鍵,然後將表中對應該鍵的值作為替換字串。
舉例,格式轉換器:將LATEX風格的命令(\example{text})轉換成XML風格的(<example>text</example>)。
function latextoxml (s)
s=string.gsub(s,\\(%a+)(%b{}),function (tag,body)
body=string.sub(body,2,-2) --移除括號
body=toxml(body) --巢狀
return string.format(“<%s>%s<%s>”,tag,body,tag)
return s
end
)
string.gmatch:該函式可以遍歷作為引數的字串中所有出現的指定模式,其常常這樣使用,如例:
for w in string.gmatch(s,”%a+”) do
……
end