Lua闭包

前提概念

词法定界:当一个函数内嵌套另一个函数的时,内嵌函数可以访问外部函数的局部变量,这种特征叫做词法定界。

第一类值:在Lua中,函数是一个值,它可以存在于变量中、可以作为函数参数,也可以作为返回值return。

upvalue:内嵌函数可以访问外部函数已经创建的局部变量,这些局部变量则称为该内嵌函数的外部局部变量(即upvalue)。

Lua中upvalue存储结构:GC信息、指向原型(Prototype)的指针、若干指向upvalue指针
在这里插入图片描述

一个upvalue有两种状态:open和closed。

当upvalue创建时,是open状态,并且它的指针指向Lua栈中对应的变量。

当Lua关闭了一个upvalue,upvalue指向的值被复制到upvalue结构内部,并且指针也相应进行调整。如图所示:
在这里插入图片描述

定义

闭包(closure)是由一个函数和该函数会访问父函数的外部局部变量(upvalue)组成的实体,主要应用在嵌套函数和匿名函数里。

简单理解,闭包由三部分组成:外部函数+外部函数的upvalue+内部函数(闭包函数)

应用

1、闭包的数据隔离
不同实例上的两个不同闭包,闭包中的upvalue变量各自独立,从而实现数据隔离

function func()
  -- 局部变量 index 保存在函数内部中
  local index = 0
  return function()
    print("index is: ", index)
    index = index + 1
  end
end

-- Test
local f1 = func()
f1() -- index is: 0
f1() -- index is: 1

local f2 = func()
f2() -- index is: 0
f2() -- index is: 1

2、闭包的数据共享
两个闭包共享一份变量upvalue,闭包创建时需要的变量不在堆栈上,引用的是更外部函数的局部变量(即upvlaue),变量(对应于示例中的 变量n)是同一个,引用也指向同一个地方,从而实现对共享数据进行访问和修改。

function shareVar(n)
    local function func1()
        print(n)
    end
    
    local function func2()
        n = n + 10
        print(n)
    end
    return func1,func2
end
--创建闭包,f1,f2两个闭包共享同一份upvalue
local f1,f2 = shareVar(1024) 

f1() -- 输出1024
f2() -- 输出1034
f1() -- 输出1034
f2() -- 输出1044

3、利用闭包实现简单的迭代器

迭代器只是一个生成器,本身不带循环。需要在循环里面去调用它。

--- 利用闭包实现iterator,iterator是一个工厂,每次调用都会产生一个新的闭包,该闭包内部包括了upvalue(t,i,n)
--- 因此每调用一次该函数都会产生闭包,那么该闭包就会根据记录上一次的状态,以及返回table中的下一个元素
function iterator(t)
    local i = 0
    local n = #t
    return function()
        i = i + 1
        if i <= n then
            return t[i]
        end
    end
end

testTable = {1,2,3,"a","b"}

-- while中使用迭代器
iter1 = iterator(testTable) --调用迭代器产生一个闭包
while true do
    local element = iter1()
    if nil == element then
        break;
    end
    print(element)
end

-- for中使用迭代器
for element in iterator(testTable) do --- 这里的iterator()工厂函数只会被调用一次产生一个闭包函数,后面的每一次迭代都是用该闭包函数,而不是工厂函数
    print(element)
end

4、创建安全的运行环境(沙盒)

如,通过使用闭包重定义函数 io.open 来限制一个程序能够访问的文件

do
    local oldOpen = io.open
    local accessOk = function(filename, mode)
      --<权限访问检查>
    end
    io.open = function (filename, mode)
        if accessOk(filename, mode) then
          return oldOpen(filename, mode)
        else
          return nil, "access denied"
        end
    end
end

参考资料

【Unity游戏开发】浅谈Lua和C#中的闭包

lua深入理解闭包

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值