闭包和upvalue

lua构建一个新的函数时, 会创建一个函数对象, 其中包含了函数本身的原型还有函数使用到的外部变量或者常量. 当这个新的函数处于某个函数内部, 我们将这个对象称之为闭包, 它所引用的外部函数的局部变量叫做upvalue.

下面是一个例子:

function f1(n)local upvalue = "hello"local f2 = function()print(upvalue .. " " .. n)endreturn f2
endg1 = f1(500)
g1()
print(g1)g2 = f1(1500)
g2()
print(g2)$ luajit copy.lua
$ hello 500
$ function: 0x00921ae0
$ hello 1500
$ function: 0x00926f28

每次调用f1将生成一个以f2为函数原型, 加上两个upvalue值(n, upvalue)的新函数(闭包). 每个新的闭包保持同一函数原型, 分别保存不同的upvalue. 严格来说, 闭包属于动态的概念, 是在程序运行阶段确定的.

upvalue值的作用域

upvalue实际上是闭包的外部函数的局部变量, 存在于外部函数的堆栈中, 在外部函数的执行过程中, 闭包通过访问外部函数堆栈的upvalue引用来访问upvalue, 一旦外部函数的调用过程完毕, 函数的堆栈被清空, upvalue也会被清除, 此时闭包会将upvalue复制到自己的函数堆栈中以便使用. 外部函数(也可以是闭包)执行完毕之前, 内部的闭包和其子闭包使用的都是外部函数堆栈中的那一份, 任何修改都会影响所有的函数(外部函数, 闭包和其子闭包), 当外部函数执行完毕后, 内部的闭包和其子闭包使用的是内部闭包从外部函数复制的那一份, 可以以此类推到最里层的闭包. 下面举例说明.

function f1(n)local upvalue = "hello"local f0 = function()local f2 = function()n = n * 2print(upvalue .. " f2 " .. n)endlocal f3 = function()print(upvalue .. " f3 " .. n)endprint(upvalue .. " f0 " .. n)return f2, f3endg1, g2 = f0()g1()g2()print(upvalue .. " f1 " .. n)return f0
endg0 =  f1(500)$ luajit copy.lua
$ hello f0 500
$ hello f2 1000
$ hello f3 1000
$ hello f1 1000

f1是外部函数, n是其内部变量, 也是内部的f2, f3形成的闭包的upvalue. 要注意的是, 每次进入f1时, 变量n都是不同的, 生成的闭包共享和保存的是当次进入外部函数时的局部变量.

闭包的作用

闭包的主要作用有两个, 一是简洁, 不需要在不使用时生成对象, 也不需要函数名, 二是可以捕获外部变量形成不同的调用环境. 从其名称可以看出来, 闭包的最主要作用是后者, 即可以捕获外部变量.

下面举例说明:

function f1()local i = 0return function()i = i + 1return iend
endg1 = f1()
g2 = f1()print("g1 " .. g1())
print("g1 " .. g1())print("------------------------")print("g2 " .. g2())
print("g2 " .. g2())$ luajit test.lua
> g1 1
> g1 2
> ------------------------
> g2 1
> g2 2

每次调用f1时会生成不同的局部变量i(值为函数定义时的初始值), 此时闭包将i保存和使用, 与另外的闭包独立开来. g1和g2共享一份函数定义和upvalue初始值, 但是调用环境独立.

这种特性最典型的使用场景是迭代器:

function f1(t)local i = 0return function()i = i + 1return t[i]end
endt = {"111", "heell", 5, 6, "3333"}
for e in f1(t) doprint(e)
end$ luajit test.lua
> 111
> heell
> 5
> 6
> 3333

lua中的闭包(closure或者匿名函数)的作用相关推荐

  1. 两个函数彻底理解Lua中的闭包

    本文通过两个函数彻底搞懂Lua中的闭包,相信看完这两个函数,应该能理解什么是Lua闭包.废话不多说,上 code: 1 --[[************************************ ...

  2. colsure php_PHP_PHP中Closure类的使用方法及详解,Closure,匿名函数,又称为Anonym - phpStudy...

    PHP中Closure类的使用方法及详解 Closure,匿名函数,又称为Anonymous functions,是php5.3的时候引入的.匿名函数就是没有定义名字的函数.这点牢牢记住就能理解匿名函 ...

  3. Rust Closure 闭包解析(匿名函数)

    Rust Closure 闭包解析(匿名函数) 文章目录 Rust Closure 闭包解析(匿名函数) 正文 1. 简单闭包 - 纯粹的匿名函数 2. 捕获上下文 & FnOnce.FnMu ...

  4. 匿名函数php作用,深入理解PHP中的匿名函数

    匿名函数的作用就是扩大函数的使用功能,在PHP(PHP培训 php教程 ) 5.3以前,传递Callback的方式,我们只有俩种选择: ◆字符串的函数名 ◆使用create_function的返回 在 ...

  5. php debug_print_backtrace,php中debug_backtrace、debug_print_backtrace和匿名函数用法实例

    本文实例讲述了php中debug_backtrace.debug_print_backtrace和匿名函数用法.分享给大家供大家参考.具体分析如下: debug_print_backtrace() 是 ...

  6. python中的闭包(closure)

    背景 本文尝试介绍Python中的闭包(closure),包括闭包是什么? 为什么要使用闭包?如何使用闭包? 嵌套函数及非局部变量 在介绍闭包之前,需要先明白什么是嵌套函数和非局部变量.在一个函数(f ...

  7. js中的匿名函数的作用以及用法讲解

    匿名函数顾名思义指的是没有名字的函数,在实际开发中使用的频率非常高!也是学好JS的重点. 释义:匿名函数,就是没有实际名字的函数. 小试牛刀,首先我们声明一个普通函数: //声明一个普通函数,函数的名 ...

  8. python中匿名函数的作用_什么是Python中的匿名函数

    匿名函数 lambda x , y : x+y 1.匿名的目的就是要没有名字,给匿名函数赋给一个名字是没有意义的. 2.匿名函数的参数规则.作用域关系与有名函数是一样的. 3.匿名函数的函数体通常应该 ...

  9. Closure 代表匿名函数的类

    Closure 用于获取并使用匿名函数.将匿名函数绑定到具体的类,从而实现对匿名函数的更多控制. 举个例子: #不绑定,直接使用匿名函数$f = function ($var){return $var ...

最新文章

  1. 【原创】MyEclipse反编译添加jadclipse_3.3.0 曲折的完美解决
  2. Parallels Desktop 16 Win11虚拟机将继续正常运作,但将无法连接网络
  3. C#中几种换行符,不同操作系统各不相同【转】
  4. 【OpenCV】IplImage类型图像ROI矩形区域的快速获取
  5. 通过google app engine 在google cloud 部署支持quic的Java web 应用(多种方式)
  6. path:path在路由中的使用
  7. python经典算法--------冒泡排序
  8. 11月16日云栖精选夜读:阿里云 oss JavaScript客户端签名文件上传 vue2.0
  9. tesseract 配置文件
  10. sqlserver 存储过程 分页搜索查询
  11. python二分法代码_Python的算法之二分法
  12. hypermesh10的安装
  13. SQLite快速入门
  14. Codeforces #123D: 后缀数组+单调栈
  15. 轻松学习Linux之入门篇
  16. mysql索引失效的几种情况
  17. iPhoneXSM屏幕适配、 各机型的逻辑分辨率
  18. Oracle:Locked by transaction: console [表名]
  19. snaker并行任务示例
  20. 无线射频专题《射频合规,ISM频段》

热门文章

  1. Java之智力题【史上最全】
  2. midas显示代理服务器错误,[转载]在使用桥博、midas的时候经常会遇到的问题
  3. 豆瓣Top250电影爬虫
  4. 一般线性模型、混合线性模型、广义线性模型
  5. [笔记] JSP 与 JSPX 语法差异对比 [草稿,待续]
  6. 爬虫逆向基础,认识 SM1-SM9、ZUC 国密算法
  7. vs2013 调试出现error C1083无法打开包括的文件
  8. (一)SQL语言_数据库_学习笔记
  9. 戴尔G3 3590 Opencore引导Mac 11.5.1 BigSur 完美驱动
  10. 业务中立_网络中立性的终结了吗?