文档章节

lua闭包

 安卓农民种苹果
发布于 2015/07/29 11:05
字数 876
阅读 48
收藏 4

    闭包(closure)是由一个函数和该函数会访问到的非局部变量(upvalue)组成,其中非局部变量是指不在局部作用范围内定义的一个变量,但同时又不是一个全局变量,主要应用在嵌套函数和匿名函数中。我们看下面的例子:

function new()
	local i = 0
	return function()
		i = i + 1
		return i
 	end
end

local new1 = new()
print(new1())
print(new1())

    输出:

1
2

    上面的代码中,new函数返回了一个函数,而这个返回的匿名函数就是闭包组合部分的函数,而i则是非局部变量。在看一下下面的例子:

function test(num)
	local function output()
		print(num)
	end

	return output
end

local fun1 = test(10086)
fun1()

local fun2 = test(10000)
fun2()

    这里fun1以及fun2的函数体时相同的,都是output的函数体,但是输出不同。因为fun1和fun2实际上是两个闭包,他们都拥有局部变量num的独立实例。事实上,lua编译一个函数时,会为它生成一个原型,其中包括了函数体对应的虚拟机指令、函数用到的常量值和一些调试信息。在运行的时候,每当lua执行一个函数的时候,他会创建一个新的数据对象,其中包含了相应函数原型的引用以及一个由所有upvalue引用组成的数组,而这个数据对象就是闭包。由此可见,函数是编译期的概念,而闭包时运行期的概念。

    非局部变量实际上指的是变量而不是值,这些变量可以在内部函数之间共享,即upvalue提供一种闭包之间共享数据的方法。看下面的例子:

function share(n)
	local function fun1()
		print(n)
	end

	local function fun2()
		n = n + 1
	end

	return fun1,fun2
end

local f1,f2 = share(10086)
f1()
f2()
f1()
f2()
f1()

    输出:

10086
10087
10088

    f1,f2都是闭包,他们共享了一个非局部变量n,当lua发现两个闭包的非局部变量指向的是当前堆栈上的相同变量时,只生成一个拷贝,然后让这两个闭包共享该拷贝,这样任意一个闭包对该非局部变量就行修改都会影响到其他闭包。

    闭包在创建的时候他的非局部变量就已经不在堆栈上的情况也是有的,这是因为内嵌函数能引用更外层外包函数的局部变量,如下例:

function test(n)
	local function fun()
		local function inner1()
			print(n)
		end

		local function inner2()
			n = n + 1
		end

		return inner1,inner2
	end

	return fun
end

local t = test(10086)
local f1,f2 = t()
f1()
f2()
f1()

local g1,g2 = t()
g1()
g2()
g1()

f1()

    输出:

10086
10087
10087
10088
10088

    从输出我们可以看出闭包f1,f2,g1,g2都共有同一个upvalue,这是因为在创建inner1,inner2这两个闭包被创建时堆栈上根本未找到n的踪影,而是直接使用闭包fun的upvalue。t = test(10086)之后,t这个闭包一定已把n妥善保存好了,之后f1、f2如果在当前堆栈上未找到n就会自动到他们的外包闭包的upvalue引用数组中去找,并把找到的引用值拷贝到自己的upvalue引用数组中。所以f1、f2、g1和g2引用的upvalue实际也是同一个变量,而刚才描述的搜索机制则确保了最后他们的upvalue引用都会指向同一个地方。

    


© 著作权归作者所有

上一篇: lua协程
下一篇: lua函数深入了解
粉丝 2
博文 16
码字总数 13696
作品 0
广州
私信 提问
在C函数中保存状态:registry、reference和upvalues

C函数可以通过堆栈来和Lua交换数据,但有时候C函数需要在函数体的作用域之外保存某些Lua数据,那么我们想到全局变量或static变量,这样做的缺点是:(1)为Lua设计C函数库时,导致不可重入;...

borey
2016/01/13
58
0
编译原理之学习 lua 3.1 (七) Closure 闭包支持

lua 3.1 与其前一个版本 3.0 比, 有了很大的变化, 可参见历史文件 HISTORY. 我们关心的有: 1. 解析由 LR 的变成手写的 LL 递归下降解析器了, 文法变化,代码生成变化了; 2. 新概念: 闭包 (clo...

刘军兴
2013/12/28
890
0
lua 中神奇的表(table)

最近在尝试配置 awesome WM,因此粗略地学习了一下 lua 。 在学习过程中,我完全被表(表)在 lua 中的应用所镇住了。 表在 lua 中真的是无处不在:首先,它可以作为字典和数组来用;此外,它...

04%
2018/07/05
0
0
Lua 学习笔记(三)—— 表达式

1 数学运算操作符 1.1 操作符 Lua 中的 操作符与 C 语言中的操作符虽然都是取模的含义,但是取模的方式不一样。 在 C 语言中,取模操作是将两个操作数的绝对值取模后,在添加上第一个操作数的...

tangyikejun
09/29
0
0
lua的私有性(privacy)

  很多人认为私有性是面向对象语言的应有的一部分。每个对象的状态应该是这个对象自己的事情。在一些面向对象的语言中,比如C++和Java你可以控制对象成员变量或者成员方法是否私有。其他一...

jeffjade
2014/11/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 如果是个帅小伙你愿意和他出去吗

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 小小编辑推荐:《Ghost 》游戏《死亡搁浅》原声 《Ghost 》游戏(《死亡搁浅》原声) - Au/Ra / Alan Walker 手机党少年们想听歌,请使劲儿戳...

小小编辑
29分钟前
28
3
java通过ServerSocket与Socket实现通信

首先说一下ServerSocket与Socket. 1.ServerSocket ServerSocket是用来监听客户端Socket连接的类,如果没有连接会一直处于等待状态. ServetSocket有三个构造方法: (1) ServerSocket(int port);...

Blueeeeeee
今天
6
0
用 Sphinx 搭建博客时,如何自定义插件?

之前有不少同学看过我的个人博客(http://python-online.cn),也根据我写的教程完成了自己个人站点的搭建。 点此:使用 Python 30分钟 教你快速搭建一个博客 为防有的同学不清楚 Sphinx ,这...

王炳明
昨天
5
0
黑客之道-40本书籍助你快速入门黑客技术免费下载

场景 黑客是一个中文词语,皆源自英文hacker,随着灰鸽子的出现,灰鸽子成为了很多假借黑客名义控制他人电脑的黑客技术,于是出现了“骇客”与"黑客"分家。2012年电影频道节目中心出品的电影...

badaoliumang
昨天
16
0
很遗憾,没有一篇文章能讲清楚线程的生命周期!

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。 ...

彤哥读源码
昨天
19
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部