又翻起了programming in lua這本書了,而且又看到 感謝貢獻之人這段代碼,今天就對這段代碼做下分析。代碼如下:
-- file: 'thanks.lua'
-- desc: to print the list of the contributing guys
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
helpful_guys = {
"----參與翻譯----",
"buxiu", "鳳舞影天", "zhang3",
"morler", "lambda", "sunlight",
"\n",
"----參與校對----",
"鳳舞影天", "doyle", "flicker",
"花生魔人", "zhang3", "Kasi",
"\n"
}
for e in list_iter( helpful_guys ) do
print(e)
end
對於這段代碼,我們分兩個部分來講,第一部分是閉包,第二部分是範式for的運行過程.
首先先講閉包,簡單一點說,閉包就是 一個內部函數,它可以訪問一個或多個外部函數的外部局部變量
結構:包含兩個函數,一個是閉包自己,一個是工廠(創建閉包的函數)
-- 這裏list_iter函數是創建閉包的工廠
function list_iter( t )
local i = 0
local n = table.getn( t )
-- 匿名函數,list_iter函數的返回值
return function ()
-- 變量i、n和t相對於這個匿名函數,是個外部函數(list_iter)的局部變量
i = i + 1
if i <= n then return t[i] end
end
end
先看下上面的list_iter函數,它的返回值是一個函數,這個函數保存着三個外部的局部變量i,n和t
大家想一下:
fFunc = list_iter( {"a", "b"} )
運行list_iter的返回值就是一個函數, 它保存了三個值,i=0, n=2, t={“a”, “b”}
第一次運行fFunc函數, 即
print( fFunc() )
輸出結果爲 a
因爲 fFunc 它是一個函數,運行的時候
i=i+1 這時i=0+1=1
t[1] 就是 a
運行完之後,這個fFunc的保存的 外部的局部變量 i變成了1
同理再運行一下 fFunc時,
輸出的結果爲 b
同時,這個fFunc的保存的 外部的局部變量 i變成了2
這時候再運行一下的時候,結果就是nil, 因爲
i=2+1 等於 3
i<=n不成立了(3<=2不成立)
所以接下來運行的時候,結果都是爲nil,
但是每運行一次的時候,fFunc這個閉包的局部變量 i就會加1
function iter_list( t )
local i = 0
local n = table.getn(t)
return function()
i = i + 1
print( "i=", i )
if i<= n then
return t[i]
end
end
end
fFunc = iter_list( {"a", "b"} )
print( fFunc() )
print( fFunc() )
print( fFunc() )
print( fFunc() )
運行結果:
接下來講一下範式for的運行過程
其語法如下
for <var-list> in <exp-list> do
<body>
end
其中
var-list 是一個或多個以逗號分割的變量名列表
exp-list 是一個或多個以逗號分割的表達式列表,迭代函數(閉包),狀態常量和控制變量
通常情況下 exp-list 爲:迭代工廠的調用。 即: iter_list() 其返回值是一個閉包
其運行過程爲:
do
-- _f爲迭代函數,_s爲狀態常量,_var爲控制變量
local _f, _s, _var = explist
while true do
-- 迭代函數的參數有兩個
-- 第一個是狀態常量_s, 這個值是explist返回的第二個參數
-- 第二個是控制常量,第一次的值是explist返回的第三個參數,後面的值是上次運行_f返回的第一個返回值
local var_1, ... , var_n = _f( _s, _var )
-- 接下來_f的第二個參數,變成上一次運行_f返回的第一個值
_var = var_1
-- 如果控制變量爲nil就結束
if _var == nil then
break
end
block
end
end
上面的解釋可能一開始看不懂,沒關係,接下來根據實例來說明一下,這裏用最開始那個感謝的函數來說明:
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
helpful_guys = {
"----參與翻譯----",
"buxiu", "鳳舞影天", "zhang3",
"morler", "lambda", "sunlight",
"\n",
"----參與校對----",
"鳳舞影天", "doyle", "flicker",
"花生魔人", "zhang3", "Kasi",
"\n"
}
-- 這裏 in 後面的結果,我們希望是一個迭代函數,一個狀態常量,一個控制常量
-- 但是這裏是 list_iter( helpful_guys )
-- 也就是說 local _f, _s, _var = list_iter( helpful_guys )的返回值
-- 因爲list_iter只有一個返回值,所以這裏的三個變量分別爲
-- _f 爲閉包, _s = nil, _var = nil
for e in list_iter( helpful_guys ) do
-- 第一次運行_f的時候,返回值是helpful_guys的第一個元素;"----參與翻譯----"
-- 根據上面分析for的運行過程,可知,這裏就是一直運行_f函數,直到其返回值爲nil就就結束
print(e)
end
上面的
for e in list_iter( helpful_guys ) do
print( e )
end
等價於
_f, _s, _var = list_iter( helpful_guys )
for e in _f, _s, _var do
print( e )
end
運行的_f的過程中,其實是有傳入狀態常量_s,和後續變化的控制變量_var,只是這裏閉包函數沒有參數而已
我們可以修改一下迭代工廠,就可以看到狀態常量_s和控制變量_var
function list_iter( t )
local i = 0
local n = table.getn( t )
-- _s爲狀態常量,其值是迭代工廠返回的第二個值,這裏就是 "我是狀態常量"
-- _var爲控制變量,第一次是迭代工廠返回的第三個值,後續是閉包運行返回的第一個值
return function ( _s, _var )
print( "狀態常量:", _s )
print( "控制量:", _var )
i = i + 1
if i <= n then return t[i] end
end, "我是狀態常量", "我是初始的控制變量"
end
for e in list_iter( {"a"} ) do
print(e)
end
運行結果:
上面就是從例子中學到的閉包和範式for的運行過程,有什麼問題,歡迎留言討論