Lua函数以及闭合函数的理解
Lua函数以及闭合函数的理解
来源 http://blog.csdn.net/mydad353193052/article/details/48731467
词法域和第一类型
在C/C++,C#或者Java等传统语言中,一个函数A,如果想调用另一个函数B,并且B需要访问A中的变量,那么A就需要向B传递参数,参数形式可以是普通类型,指针,或者引用。(C#中有out输出参数和ref引用,专门的关键字来做这件事)但是在Lua中,呵呵,不必如此。
Lua中有一个“词法域”的概念。即B可以访问他所需要访问的所有“非局部变量”(后面会解释为什么叫双引号下的非局部变量)。但是这一切的说说笑笑都必须要有前提——在Lua中,函数是“第一类型”。就是说函数和int,string,float等泛泛之辈一样,都TM是类型,都是菜。而函数名则可以理解为,拿着函数实体的变量。请看下面这个例子:
- a = {p = print}
- a.p("hello bitch") ---hello bitch
- print = math.sin ---'print'现在是正弦函数
- a.p(print(1)) ---0.8414709848079
- sin = a.p ---'sin'现在是print函数
- sin(10 .. 20) ---1020
正所谓似鸡非鸡,似鸭非鸭。鸡有可能变鸭,鸭也可以手术变鸡。
那么说函数是变量,他还就蹬鼻子上脸,给变量一会看看——Lua常见的函数编写方式:
function foo(x) return 2*x end
其实他是一下这句话的简化形式:
foo = function (x) return 2*x end
所以,一个函数的定义实际就是一条赋值语句,这条语句首先创建一个函数类型的值,然后将这个值赋予这个函数变量。也可以将表达式 function(x)<body>end 理解为一种函数的构造式。就像table的构造式 {} 一样。
将这种函数构造式的结果称为一个“匿名函数”。下面这个例子就是使用匿名函数来做参数。
table.sort,是对一个table表中的内容按照一定规则排序。但是sort并没有提供具体的规则,规则的指定完全交给使用者自己定义。升序,降序,按key顺序等等。sort接收两个元素,第一个元素是table,第二个元素就是排序规则。那我们在这里就用匿名函数来做这个sort的第二个元素——排序规则。
- network = {
- {name = "grauna", NICK = "lululala"},
- {name = "araadd", NICK = "bababu" },
- {name = "oo", NICK = "ppreea"},
- {name = "zzdafae", NICK = "ddadf"},
- }
- for i=1, #network do
- print(network[i].name)
- end
- table.sort(
- network,
- function(a,b)
- return (a.name > b.name)
- end
- )
- for k,v in pairs(network) do
- print(k,v.name)
- end
二、闭合函数
在理解了上面这些思想之后,我们来想想closure。还是刚才说的, A==>>B,A是B的外部函数,B可以访问A中的局部变量。直接上菜说:
- names = {"Peter", "Paul", "Mary"}
- grades = {Mary = 10, Paul = 7, Peter = 8}
- table.sort(
- names,
- function(n1, n2)
- return grades[n1] > grades[n2]
- end
- )
- for k,v in ipairs(names) do
- print(k,v)
- end
用一个单独的函数来调用:
- names = {"Peter", "Paul", "Mary"}
- grades = {Mary = 10, Paul = 7, Peter = 8}
- function sortbygrade(cnames, cgrades)
- table.sort(
- cnames,
- function(n1, n2)
- return cgrades[n1] > cgrades[n2]
- end
- )
- return cnames
- end
- for k,v in ipairs(sortbygrade(names, grades)) do
- print(k,v)
- end
输出结果同上。
可见,传递给sort的匿名函数可以访问参数cgrades,而cgrades是外部函数sortbygrade的局部变量。而在这个匿名函数内部,cgrades既不是全局变量也不是局部变量,将其称为一个“非局部的变量”。
再看下面这个例子:
- function newCounter()
- local i = 0
- return function()
- i = i + 1
- return i
- end
- end
- c1 = newCounter()
- print(c1()) ---1
- print(c1()) ---2
- c2 = newCounter()
- print(c2()) ---1
- print(c1()) ---3
- print(c2()) ---2
初次见到这个输出结果,有些摸不到后脑勺。为啥第二次print(c1())结果是2呢?
仔细一想,这还得说那句老话,Lua中函数是第一类型。(别骂娘)
你想想,在C++中,如果你定义一个int a=1;那么编译器只会在栈中开辟一块空间来存a,直至释放。
那么c1也是这回事儿,你第二次print,实际上还是在 第一次在栈中开辟的那块空间里 折腾。所以此时栈中的local i已经不是当年那个 = 0 的小姑娘了,人家已经长成 1 了。所以你再print,就在1的基础上变成2了。
而c2跟c1不一样,c2是隔壁家的姑娘,又是一块栈空间,所以c2的第一次还是1。 以此类推,后面的print结果就顺理成章了。
Lua函数以及闭合函数的理解的更多相关文章
- lua闭合函数
function count( ... ) return function( ... ) i = i+ return i end end local func = count(...) print(f ...
- [Lua] 迭代器 闭合函数 与 泛型for
首先看看一下闭合函数(closure),见如下代码: function newCounter() local i = 0 -- 非局部变量(non-local variable) return fun ...
- Lua中的closure(闭合函数)
词法域:若将一个函数写在另一个函数之内,那么这个位于内部的函数便可以访问外部函数中的局部变量,这项特征称之为“词法域”. 例:假设有一个学生姓名的列表和一个对应于没个姓名的年级列表,需要根据每个学生的 ...
- Lua中调用C函数
Lua利用一个虚拟的堆栈来给C传递值或从C获取值.每当Lua调用C函数,都会获得一个新的堆栈,该堆栈初始包含所有的调用C函数所需要的参数值(Lua传给C函数的调用实参),并且C函数执行完毕后,会把返回 ...
- lua学习之深入函数第一篇
深入函数第一篇 函数是第一类值,具有特定的词法域 第一类值 第一类值的意思是函数与 lua 中的其他类型如数字,字符串具有相同的权力 函数可以存储到全局变量或局部变量变量,还可以存储到 table 中 ...
- 深入理解javascript函数定义与函数作用域
最近在学习javascript的函数,函数是javascript的一等对象,想要学好javascript,就必须深刻理解函数.本人把思路整理成文章,一是为了加深自己函数的理解,二是给读者提供学习的途径 ...
- lua如何调用C++函数
第一步是定义函数.所有在Lua中被调用的C/C++函数将使用下面一类指针进行调用: typedef int (*lua_CFunction) (lua_State *L); 换句话说,函数必须要以Lu ...
- Lua中的常用函数库汇总
lua库函数 这些函数都是Lua编程语言的一部分, 点击这里了解更多. assert(value) - 检查一个值是否为非nil, 若不是则(如果在wow.exe打开调试命令)显示对话框以及输出错误调 ...
- lua堆栈操作常用函数学习二
/* ** basic stack manipulation */ LUA_API int <strong> (lua_gettop) (lua_State *L); </str ...
随机推荐
- mysql操作sql的小技巧
本篇集中整理一下执行sql的小技巧,这种方式不仅带来了操作上的便捷,也可以保证数据可以数据的安全性. 1:查询数据(保证查询性能) 首先想先解释一下 SELECT * 和 SELECT t.id , ...
- 【2016美团】浏览器和服务器在基于https进行请求链接到数据传输过程中,用到了如下哪些技术
A.非对称加密技术 B.对称加密技术 C.散列(哈希)算法 D.数字证书 答案:ABCD HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数 ...
- Ionic3学习笔记(三)禁止横屏
本文为原创文章,转载请标明出处 目录 安装 使用 参数 1. 安装 命令行输入 ionic cordova plugin add cordova-plugin-screen-orientation n ...
- 将图标LOGO之类的图形图像转换成字体调用方法大全
借鉴百度对此标题的评价: 使用字体图标的优势 字体图标除了图像清晰度之外,比位图还有哪些优势呢. 适用性:一个图标字体比一系列的图像(特别是在Retina屏中使用双倍大小的图像)要小.一旦图标字体加载 ...
- 使用IGP和BGP的配合达到降低路由容量目的的实验与总结
概述 1.先说结论,通过eBGP协议,可以显著降低对非核心路由器的路由容量要求,因为核心路由器的数量明显少于非核心路由器,所以,通过此措施即联通网络,又降低设备要求,非常适宜大型网络. 2.因为网络规 ...
- ios获取本机网络IP地址方法
#include <ifaddrs.h> #include <arpa/inet.h> - (NSString *)getIPAddress { N ...
- 根据Dockerfile创建docker dotnet coer 镜像
那我们先来看看Dockerfile文件内容,注意这个文件是没后缀名的. #依赖原始的镜像,因为我们是要创建dotnet coer镜像,所以我就用了官方给的镜像[microsoft/dotnet:lat ...
- ABAP 数值四舍五入函数
VALUE '12.5445' , dat1 . VALUE '12.540'. * 方法一 CALL FUNCTION 'HR_NZ_ROUNDING_DECIMALS' EXPORTING val ...
- JAVA提高五:注解Annotation
今天我们学习JDK5.0中一个非常重要的特性,叫做注解.是现在非常流行的一种方式,可以说因为配置XML 比较麻烦或者比容易查找出错误,现在越来越多的框架开始支持注解方式,比如注明的Spring 框架, ...
- windows server git
我有一个阿里云,windows server,我想把代码放阿里云 我去做git,只需要安装copssh 下载git https://git-for-windows.github.io/ 下载Copss ...