从例子中学习闭包和范式for

又翻起了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的运行过程,有什么问题,欢迎留言讨论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值