閉包函式到底是什麼?有什麼用?
轉載請註明出處即可,無需經過我本人同意。
以下內容為網上的內容加上本人的理解,如有侵權,請通知本人刪除文章。
閉包函式是什麼:
首先看如下程式碼,你是否瞭解其真正的意義:
function test()
local i=0
return function()
i=i+1
return i
end
end
doTest=test()
print(doTest()) --輸出1
print(doTest()) --輸出2
你可能有這樣的疑問:
1. 呼叫test()返回的函式doTest()時,變數 i 的定義在哪?
2. test()中的i不是區域性變數嗎?為什麼返回的函式還能呼叫。
如果你有這樣的疑問,請接著往下看。
首先,瞭解幾個概念:
詞法定界:當一個函式內巢狀另一個函式的時候,內函式可以訪問外部函式的區域性變數,這種特徵叫做詞法定界。而這些變數就被稱為該內嵌函式的upvalue,upvalue實際指的是變數而不是值,這些變數可以在內部函式之間共享。
閉包:通過呼叫含有一個內部函式加上該外部函式持有的外部區域性變數(upvalue)的外部函式(外部函式就是工廠)產生的一個例項函式。
閉包組成:外部函式+外部函式建立的upvalue+內部函式(閉包函式)
如上面的函式test(),
test()就是外部函式,
外部函式的區域性變數local i=0就是upvalue(也叫做非區域性變數,之所以叫做非區域性變數,是因為此變數的作用域既不是區域性變數的作用域,也不是全域性變數的作用域。),
返回的函式就是內部函式。
現在再回頭看看原來的函式,我們知道了這種形式的函式叫做閉包函式。而test()中的區域性變數i是內嵌函式的upvalue(非區域性變數),且在內部函式中共享。
重複呼叫內部函式時,每一個呼叫都會記住上一次呼叫後的值,就是說第一次呼叫doTest()之後,i 的值已經是1了。
下面再看個例子
function test()
local i=0
return function()
i=i+1
return i
end
end
doTest=test()
doAgain=test()
print(doTest()) --輸出1
print(doTest()) --輸出2
print(doAgain()) --輸出1
print(doAgain()) --輸出2
可以看到,此時執行doAgain()時 i 值並沒有在原來的基礎上增加。
原因是:
doTest,doAgain是建立在同一個函式,同一個區域性變數的不同例項上面的兩個不同的閉包。
呼叫一次test()就會產生一個新的閉包, 而閉包中的upvalue各自獨立。所以不難解釋為什麼doAgain()的i 值為什麼沒有在原來的基礎上增加了。
閉包函式有什麼用:
在for in 的迴圈中需要使用到迭代器,而迭代器需要保留上一次呼叫的狀態和下一次成功呼叫的狀態,剛好可以使用閉包的機制來實現。
建立迭代器:
function list_iter(t) --外包函式叫做工廠函式。
local i=0
local n=table.getn(t)
return function()
i=i+1
if i<=n then return t[i] end
end
end
--[[這裡的list_iter是一個工廠,每次呼叫都會產生一個新的閉包。該閉包內部包括了upvalue(t,i,n)。
因此每呼叫一次該函式產生的閉包,那麼該閉包就會根據記錄上一次的狀態,以及返回list的下一個。]]
在while中使用:
--while中使用:
t={10,20,90}
iter=list_iter(t) --呼叫迭代器產生一個閉包
while true do
--當閉包函式的i值已經等於n的值時,依然會執行閉包函式,此時返回的就是nil.
--如果沒有下面的判斷,while就會一直迴圈,並進入死迴圈。
local element=iter()
if element==nil then break end
print(element)
end
在泛型for使用
--泛型for使用:
t={10,0,29}
--這裡的list_iter()工廠函式只會被呼叫一次產生一個閉包函式,
--後面的每一次迭代都是用該閉包函式,而不是工廠函式。
for element in list_iter(t) do
print(element)
end
如果想要同時返回k,v值,需要修改工廠函式,如下所示:
function list_iter(tb)
local i = 0
return function ()
i = i + 1
--如果沒有下面這個判斷,就會一直執行。
--詳情可以看我的另一篇部落格,《Lua內容關於for迴圈的總結》
if tb[i] == nil then
return nil
end
return i,tb[i]
end
end
相關文章
- 為什麼js會有閉包JS
- Python中什麼是閉包?閉包的好處是什麼?Python
- [JS]什麼是閉包?JS
- 什麼是閉包陷阱?
- 什麼是閉包?有哪些使用場景?優缺點是什麼?
- javaScript面試題整理 --- 什麼是閉包,什麼是立即執行函式,它的作用是什麼?簡單說一下閉包的使用場景JavaScript面試題函式
- javascript中閉包是什麼JavaScript
- 函式宣告與函式表示式有什麼區別?函式
- ipa檔案證書監測有什麼用?測試安裝包有什麼用?什麼型別包需要要求資質?型別
- Oracle ASM有什麼用?為什麼用?OracleASM
- mac os 關閉sip保護有什麼好處?有什麼壞處?macOS為什麼關閉sip?Mac
- 征服 JavaScript 面試:什麼是閉包JavaScript面試
- JS 中的閉包是什麼?JS
- NLA有什麼用?原理是什麼?
- 伺服器發包指的是什麼?有什麼作用?伺服器
- css--BFC是什麼,有什麼用,怎麼用?CSS
- avast安全線vpn有什麼用如何關閉AST
- 什麼是仿函式?函式
- 一什麼是函式?函式
- 根證書是什麼?有什麼用?
- FactoryBean有什麼用Bean
- web裡什麼是Math函式,作用是什麼Web函式
- Python range()函式有什麼作用?如何使用?Python函式
- 方法(method)和函式(function)有什麼區別?函式Function
- 機器學習到底是什麼?機器學習
- ? babel到底是什麼❓Babel
- (JavaScript)函式名裡有什麼?JavaScript函式
- httpdns是個什麼技術,有什麼用httpdDNS
- RFM是什麼?這個模型有什麼用?模型
- 蘋果Feedback是什麼?有什麼用?怎麼刪除?蘋果
- javascript純函式是什麼JavaScript函式
- 為什麼不建議函式有太多引數?函式
- 請問getKey()方法是什麼,有什麼用
- Python是什麼意思?Python有什麼用?Python
- 什麼是電話機器人?有什麼用?機器人
- 影像採集卡是什麼,有什麼用處
- JSON是什麼,有什麼用,怎麼寫jsonJSON
- 什麼是seLinux?Linux關閉seLinux有什麼影響?Linux