当前位置: 首页 > article >正文

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深入理解闭包


http://www.kler.cn/news/306301.html

相关文章:

  • 基于yolov5的混凝土缺陷检测系统python源码+onnx模型+评估指标曲线+精美GUI界面
  • 【Linux C | 终端设备】Linux下 tty、ttyS*、ttyAMA*、console 的区别,以及系统输出重定向(附带代码)
  • NPM私库搭建-verdaccio(Linux)
  • 【Kubernetes】常见面试题汇总(十七)
  • Django+Vue基于OpenCV的人脸识别系统的设计与实现
  • CleanMyMac X 4.15.6正式版 mac直装破解版
  • 小阿轩yx-案例:Zabbix监控kubernetes云原生环境
  • ios 用JXCategoryView 库实现tab滑动切换viewController
  • 破解AI生成检测:如何用ChatGPT降低论文的AIGC率
  • Redis Universe: 探索无边界的数据处理星系
  • 网络安全 day6 --- 抓包技术HTTPS协议小程序PC应用WEB转发联动
  • Spring Boot-分布式系统问题
  • 运算符学习
  • Selenium元素定位:深入探索与实践
  • 【Java EE】线程安全问题的原因与解决方案
  • 滚雪球学SpringCloud[3.2讲]:Hystrix:熔断与降级详解
  • 基于JDK1.8和Maven的GeoTools 28.X源码自主构建实践
  • Python基础语法(3)下
  • 计算机毕业设计 网上体育商城系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
  • 实验一 番外篇 虚拟机联网与DHCP服务器
  • 实战千问2大模型第三天——Qwen2-VL-7B(多模态)视频检测和批处理代码测试
  • 【UI】element ui table(表格)expand实现点击一行展开功能
  • Blue Screen of Death(BSOD)
  • Presto
  • 使用容器技术快速入门MinIO
  • Python 中 Locale.Error: Unsupported Locale Setting 错误
  • iCAM06: A refined image appearance model for HDR image rendering
  • 分享Vue3.5最新变化
  • C++高性能线性代数库Armadillo入门
  • 【算法专题】穷举vs暴搜vs深搜vs回溯vs剪枝