Lua闭包

news/2025/1/15 12:13:48/

前提概念

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

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

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

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

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

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

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

定义

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

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

应用

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

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

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

lua">function shareVar(n)local function func1()print(n)endlocal function func2()n = n + 10print(n)endreturn func1,func2
end
--创建闭包,f1,f2两个闭包共享同一份upvalue
local f1,f2 = shareVar(1024) f1() -- 输出1024
f2() -- 输出1034
f1() -- 输出1034
f2() -- 输出1044

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

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

lua">--- 利用闭包实现iterator,iterator是一个工厂,每次调用都会产生一个新的闭包,该闭包内部包括了upvalue(t,i,n)
--- 因此每调用一次该函数都会产生闭包,那么该闭包就会根据记录上一次的状态,以及返回table中的下一个元素
function iterator(t)local i = 0local n = #treturn function()i = i + 1if i <= n thenreturn t[i]endend
endtestTable = {1,2,3,"a","b"}-- while中使用迭代器
iter1 = iterator(testTable) --调用迭代器产生一个闭包
while true dolocal element = iter1()if nil == element thenbreak;endprint(element)
end-- for中使用迭代器
for element in iterator(testTable) do --- 这里的iterator()工厂函数只会被调用一次产生一个闭包函数,后面的每一次迭代都是用该闭包函数,而不是工厂函数print(element)
end

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

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

lua">dolocal oldOpen = io.openlocal accessOk = function(filename, mode)--<权限访问检查>endio.open = function (filename, mode)if accessOk(filename, mode) thenreturn oldOpen(filename, mode)elsereturn nil, "access denied"endend
end

参考资料

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

lua深入理解闭包


http://www.ppmy.cn/news/1526055.html

相关文章

Mini-Omni:语言模型可以在流中听、说和思考

读论文《Mini-Omni: Language Models Can Hear, Talk While Thinking in Streaming》 目前比较火的一篇论文&#xff0c;分享给大家 论文地址&#xff1a;2408.16725v2 (arxiv.org) 项目地址&#xff1a;https://github.com/gpt-omni/mini-omni 1. 引言 近年来&#xff0c…

人工智能与机器学习原理精解【19】

文章目录 马尔科夫链概述定义与性质分类应用领域收敛性马尔科夫链蒙特卡洛方法 马尔科夫链原理详解一、定义二、特性三、数学描述四、类型五、应用六、示例定义性质转移概率矩阵应用举例结论 马尔科夫链在语音识别和语音合成中的应用一、马尔科夫链在语音识别中的应用1. 基本概…

vue3-print打印eletable某一行的数据

主页面的表格 <template><el-table :data"list"><el-table-column label"操作" align"center"><template #default"scope"><el-buttonlinktype"primary"click"handleType(scope.row)"…

【GO开发】MacOS上搭建GO的基础环境-Hello World

文章目录 一、引言二、安装Go语言三、配置环境变量&#xff08;可跳过&#xff09;四、Hello World五、总结 一、引言 Go语言&#xff08;Golang&#xff09;因其简洁、高效、并发性强等特点&#xff0c;受到了越来越多开发者的喜爱。本文将带你一步步在Mac操作系统上搭建Go语…

uni-app获取设备唯一值、静态IP以及公网IP的方法

最近开发uniapp的时候&#xff0c;想要获取设备的唯一值作为绑定设备的序列号&#xff0c;还有手动设置的IP以及联网后的公网ip&#xff0c;在插件市场找到一个插件&#xff0c;非常适合&#xff0c;链接如下&#xff1a;lrw-getip-getid&#xff0c;特意在此记录一下&#xff…

Golang | Leetcode Golang题解之第397题整数替换

题目&#xff1a; 题解&#xff1a; func integerReplacement(n int) (ans int) {for n ! 1 {switch {case n%2 0:ansn / 2case n%4 1:ans 2n / 2case n 3:ans 2n 1default:ans 2n n/2 1}}return }

操作系统的心脏:进程调度的基本过程

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持&#xff01; 进程调度是操作系统中至关重要的组成部分&#xff0c;它负责决定哪个进程应该在何时使用CPU。了解计算机进行进程调度的过程和原理,对我们了解计算机以及进行多线程编程大有帮助! 在操作系统中,进程…

SpringCloud的学习,Consul服务注册与发现、分布式配置,以及 服务调用和负载均衡

介绍 Consul 是一套开源的分布式服务发现和配置管理系统&#xff0c;由 HashiCorp 公司用 Go 语言开发。 提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用&#xff0c;也可以一起使用以构建全方位的服务网格&#xff0c;…