[Lua]lua闭包

简介: 前言在很多语言中都有闭包的概念,而在这里,我将主要对Lua语言的闭包概念进行分析与总结。希望对大家学习Lua有帮助。什么是闭包?闭包在Lua中是一个非常重要的概念,闭包是由函数和与其相关的引用环境组合而成的实体。

前言

在很多语言中都有闭包的概念,而在这里,我将主要对Lua语言的闭包概念进行分析与总结。希望对大家学习Lua有帮助。


什么是闭包?

闭包在Lua中是一个非常重要的概念,闭包是由函数和与其相关的引用环境组合而成的实体。我们再来看一段代码:

1
2
3
4
5
6
7
8
9
10
11
function newCounter()
      local i = 0
      return  function () -- 匿名函数
           i = i + 1
           return  i
      end
end
 
c1 = newCounter()
print(c1()) 
print(c1())

根据刚刚说的闭包的概念,结合上面的代码,来说说这个概念。闭包=函数+引用环境。上述代码中的newCounter函数返回了一个函数,而这个返回的匿名函数就是闭包的组成部分中的函数;引用环境就是变量i所在的环境。实际上,闭包只是在形式和表现上像函数,但实际上不是函数,我们都知道,函数就是一些可执行语句的组合体,这些代码语句在函数被定义后就确定了,并不会再执行时发生变化,所以函数只有一个实例。而闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例,就好比相同的类代码,可以创建不同的类实例一样。在看别人的文章时,看到有这样的说法:子函数可以使用父函数中的局部变量,这种行为就叫做闭包!这种说法其实就说明了闭包的一种表象,让我们从外在形式上,能更好的理解什么是闭包。至于深层次的闭包,我们接着继续。


再看闭包

首先,在Lua中,创建一个函数,就像定义一个普通类型值一样的,也就是之前的文章中说的,Lua中的函数和和普通类型是没有区别的。Lua中的函数就是所谓的“第一类值”,它可以被存放在变量或数据结构中,可以当做参数传递给另一个函数,可以是一个函数的返回值,还可以在运行期间被创建。Lua中的函数就是这样的一种“东西”,它很灵活。正如《Lua中的函数》中提到的“非局部的变量”这个概念么?这是一个非常很重要的概念,它可以理解为不是在局部作用范围内定义的一个变量,同时,它又不是一个全局变量,也就是大家说的upvalue,由于有了这样的一种变量的存在,就成全了Lua中的闭包。这种变量主要应用在嵌套函数和匿名函数里。我们都知道,可以在Lua的函数中再定义函数,也就是内嵌函数,内嵌函数可以访问外部函数已经创建的所有局部变量,而这些变量就被称为该内嵌函数的upvalue,upvalue实际指的是变量而不是值,这些变量可以在内部函数之间共享,比如以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function Fun1()
      local iVal = 10          -- upvalue
      function InnerFunc1()     -- 内嵌函数
           print(iVal)          --
      end
 
      function InnerFunc2()     -- 内嵌函数
           iVal = iVal + 10
      end
 
      return  InnerFunc1, InnerFunc2
end
 
-- 将函数赋值给变量,此时变量a绑定了函数InnerFunc1, b绑定了函数InnerFunc2
local a, b = Fun1()
 
-- 调用a
a()          -->10
 
-- 调用b
b()          -->在b函数中修改了upvalue iVal
 
-- 调用a打印修改后的upvalue
a()          -->20

上述这段简单的代码,就验证了在内嵌函数中是共享upvalue的,就好比C++类中的成员函数可以访问和修改成员变量一样。


使用闭包

可以看到闭包是数据和行为的结合体,就好比C++中的类,这样就使得闭包具有较好的抽象能力,在某些场合下,我们需要记住某次调用完成以后数据的状态,就好比C++中的static类型的变量,每次调用完成以后,static类型的变量并不会被清除。使用闭包就可以很好的完成该功能,在下一篇博文中,我将会讲到使用闭包完成迭代器功能。


总结

闭包是一个非常很总要的概念,也好理解,也难理解,简单的说,闭包就是内嵌的函数加上它可以正确访问的upvalue。很多时候,我们明白了这个道理,却不会用这个东西,所以,我们需要阅读更多的代码,参加更多的项目,去积累更多的项目经验,来丰富自己的阅历,到时候,理解层次就会上去。

相关文章
|
9月前
|
Lua语法(二)——闭包/日期和时间
Lua语法(二)——闭包/日期和时间
151 0
【Lua基础 第5章 】unpack()和pack()、Lua 中的文件 I/O、简单模式下io的部分方法、完全模式下file的部分方法、日期和时间、闭包使用
unpack()和pack()、Lua 中的文件 I/O、简单模式下io的部分方法、完全模式下file的部分方法、日期和时间、闭包使用
1065 0
【Lua基础 第5章 】unpack()和pack()、Lua 中的文件 I/O、简单模式下io的部分方法、完全模式下file的部分方法、日期和时间、闭包使用
在C++使用LUA交互,LUA实现闭包,C++/LUA相互闭包
LUA可谓是配置文件神器,具体功能用过才知道,接近两年没用了抽了俩小时熟悉了下基本的用法。 包括C/LUA堆栈操作 函数相互调用 以及LUA的闭包 C++和LUA相互闭包 想要灵活使用LUA必须先要学习 LUA和C的堆栈交互模型 类似于汇编函数调用方式了 很有意思。
1065 0
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
本文介绍了如何通过Lua脚本在Redis中实现分布式锁的原子性操作,避免并发问题。首先讲解了Lua脚本的基本概念及其在Redis中的使用方法,包括通过`eval`指令执行Lua脚本和通过`script load`指令缓存脚本。接着详细展示了如何用Lua脚本实现加锁、解锁及可重入锁的功能,确保同一线程可以多次获取锁而不发生死锁。最后,通过代码示例演示了如何在实际业务中调用这些Lua脚本,确保锁操作的原子性和安全性。
154 6
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
通过本文的介绍,我们详细讲解了 Lua 脚本在 Redis 中的作用、`eval` 命令的使用方法以及 `redis.call` 和 `redis.pcall` 的区别和用法。通过合理使用 Lua 脚本,可以实现复杂的业务逻辑,确保操作的原子性,并减少网络开销,从而提高系统的性能和可靠性。
121 13
|
5月前
|
公司用什么软件监控电脑:Lua 脚本在监控软件扩展功能的应用
在企业环境中,电脑监控软件对保障信息安全、提升效率至关重要。Lua 脚本在此类软件中用于扩展功能,如收集系统信息、监控软件使用时长及文件操作,向指定服务器发送数据,支持企业管理和运营。
79 6
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
323 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等