• 闭包函数是什么


    闭包函数是什么:

    首先看如下代码,你是否了解其真正的意义:

    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
  • 相关阅读:
    c++ 迷宫问题
    linux下恢复删除的文件
    c++ 分解数2
    c++ 平分石头
    多态
    设计模式中类的6种关系
    工厂方法模式
    设计原则之面向接口编程
    封装、继承
    便利构造器、单件模式
  • 原文地址:https://www.cnblogs.com/gyrgyr/p/7427569.html
Copyright © 2020-2023  润新知