lua 11 闭包,函数的使用
转自:http://book.luaer.cn/_41.htm
当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界。虽然这看起来很清楚,事实并非如此,词法定界加上第一类函数在编程语言里是一个功能强大的概念,很少语言提供这种支持。
下面看一个简单的例子,假定有一个学生姓名的列表和一个学生名和成绩对应的表;现在想根据学生的成绩从高到低对学生进行排序,可以这样做:
names = {"Peter", "Paul", "Mary"}
grades = {Mary = 10, Paul = 7, Peter = 8}
table.sort(names, function (n1, n2)
return grades[n1] > grades[n2] -- compare the grades
end)
假定创建一个函数实现此功能:
function sortbygrade (names, grades)
table.sort(names, function (n1, n2)
return grades[n1] > grades[n2] -- compare the grades
end)
end
例子中包含在sortbygrade函数内部的sort中的匿名函数可以访问sortbygrade的参数grades,在匿名函数内部 grades 不是全局变量也不是局部变量,我们称作外部的局部变量(external local variable)或者upvalue。(upvalue意思有些误导,然而在Lua中他的存在有历史的根源,还有他比起external local variable简短)。
看下面的代码:
function newCounter()
local i = 0
return function() -- anonymous function
i = i + 1
return i
end
end print(newCounter()) --> function: 08935750 ?
print(newCounter()) --> function: 05B09710 ? c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
匿名函数使用upvalue i保存他的计数,当我们调用匿名函数的时候 i 已经超出了作用范围,因为创建i的函数newCounter已经返回了。然而Lua用闭包的思想正确处理了这种情况。简单的说,闭包是一个函数以及它的upvalues。如果我们再次调用newCounter,将创建一个新的局部变量i,因此我们得到了一个作用在新的变量i上的新闭包。
c2 = newCounter()
print(c2()) --> 1 这里要特别注意!
print(c1()) --> 3 这里要特别注意!
print(c2()) --> 2
c1、c2是建立在同一个函数上,但作用在同一个局部变量的不同实例上的两个不同的闭包。
技术上来讲,闭包指值而不是指函数,函数仅仅是闭包的一个原型声明;尽管如此,在不会导致混淆的情况下我们继续使用术语函数代指闭包。
闭包在上下文环境中提供很有用的功能,如前面我们见到的可以作为高级函数(sort)的参数;作为函数嵌套的函数(newCounter)。这一机制使得我们可以在Lua的函数世界里组合出奇幻的编程技术。闭包也可用在回调函数中,比如在GUI环境中你需要创建一系列button,但用户按下button时回调函数被调用,可能不同的按钮被按下时需要处理的任务有点区别。具体来讲,一个十进制计算器需要10个相似的按钮,每个按钮对应一个数字,可以使用下面的函数创建他们:
function digitButton (digit)
return Button{ label = digit,
action = function ()
add_to_display(digit)
end
}
end
这个例子中我们假定Button是一个用来创建新按钮的工具, label是按钮的标签,action是按钮被按下时调用的回调函数。(实际上是一个闭包,因为他访问upvalue digit)。digitButton完成任务返回后,局部变量digit超出范围,回调函数仍然可以被调用并且可以访问局部变量digit。
闭包在完全不同的上下文中也是很有用途的。因为函数被存储在普通的变量内我们可以很方便的重定义或者预定义函数。通常当你需要原始函数有一个新的实现时可以重定义函数。例如你可以重定义sin使其接受一个度数而不是弧度作为参数:
oldSin = math.sin
math.sin = function (x)
return oldSin(x*math.pi/180)
end
更清楚的方式:
do
local oldSin = math.sin
local k = math.pi/180
math.sin = function (x)
return oldSin(x*k)
end
end
这样我们把原始版本放在一个局部变量内,访问sin的唯一方式是通过新版本的函数。
利用同样的特征我们可以创建一个安全的环境(也称作沙箱,和java里的沙箱一样),当我们运行一段不信任的代码(比如我们运行网络服务器上获取的代码)时安全的环境是需要的,比如我们可以使用闭包重定义io库的open函数来限制程序打开的文件。
do
local oldOpen = io.open
io.open = function (filename, mode)
if access_OK(filename, mode) then
return oldOpen(filename, mode)
else
return nil, "access denied"
end
end
end
lua 11 闭包,函数的使用的更多相关文章
- day11_7.11 闭包函数与装饰器
补充: callable 代表可调用的,加括号可以执行.(函数或者类) import this 查看python之禅 一.闭包函数 所谓闭包函数,就是定义在函数内部的函数,也就是函数定义的嵌套.而在 ...
- 三种语言(c++、as、lua)中函数的差异性
对于不同的语言, 尤其是静态语言和动态语言, 对于函数的定义(即如何看待一个函数)和处理截然不同.具体来说可以分为两类: 1.将函数视为第一类型值, 即函数和其他的对象一样, 都是语言中一个普通的对象 ...
- lua 函数调用 -- 闭包详解和C调用
转自:http://www.cnblogs.com/ringofthec/archive/2010/11/05/luaClosure.html 这里, 简单的记录一下lua中闭包的知识和C闭包调用 前 ...
- lua二进制操作函数
由于 Lua 脚本语言本身不支持对数字的二进制操作(例如 与,或,非 等操作),MUSHclient 为此提供了一套专门用于二进制操作的函数,它们都定义在一个“bit”表中,使用时只要requre “ ...
- Lua中的函数
[前言] Lua中的函数和C++中的函数的含义是一致的,Lua中的函数格式如下: function MyFunc(param) -- Do something end 在调用函数时,也需要将对应的参数 ...
- 深入理解Lua的闭包一:概念、应用和实现原理
本文首先通过具体的例子讲解了Lua中闭包的概念,然后总结了闭包的应用场合,最后探讨了Lua中闭包的实现原理. 闭包的概念 在Lua中,闭包(closure)是由一个函数和该函数会访问到的非局部变量 ...
- [转]lua数据结构--闭包
前面几篇文章已经说明了Lua里面很常用的几个数据结构,这次要分享的也是常用的数据结构之一 – 函数的结构.函数在Lua里也是一种变量,但是它却很特殊,能存储执行语句和被执行,本章主要描述Lua是怎么实 ...
- Lua的闭包详解(终于搞懂了)
词法定界:当一个函数内嵌套另一个函数的时候,内函数可以访问外部函数的局部变量,这种特征叫做词法定界 table.sort(names,functin (n1,n2) return grades[n1] ...
- php的匿名函数和闭包函数
php的匿名函数和闭包函数 tags: 匿名函数 闭包函数 php闭包函数 php匿名函数 function use 引言:匿名函数和闭包函数都不是特别高深的知识,但是很多刚入门的朋友却总是很困惑,因 ...
随机推荐
- May 26th, 2019. Week 22nd, Sunday
A real loser is somebody that's so afraid of not winning, they don't even try. 真正的失败者,是那些因为害怕不能成功,就连 ...
- Python入门基础学习(面向对象)
Python基础学习笔记(四) 面向对象的三个基本特征: 封装:把客观事物抽象并封装成对象,即将属性,方法和事件等集合在一个整体内 继承:允许使用现有类的功能并在无须重新改写原来的类情况下,对这些功能 ...
- Go 循环 (for)
循环类型 for: for a := 0; a < 10; a ++{ fmt.Println(a) } 在执行结束后 a == 10 while: a := 0 for a < 10{ ...
- 第05组 Beta冲刺(4/4)
第05组 Beta冲刺(4/4) 队名:天码行空 组长博客连接 作业博客连接 团队燃尽图(共享): GitHub当日代码/文档签入记录展示(共享): 组员情况: 组员1:卢欢(组长) 过去两天完成了哪 ...
- COM 编程基础
DirectX 采用了 COM 标准.而 DirectShow 是一套完全基于 COM 的应用系统.要想深入学习 DirectShow,掌握一些 COM 编程的基础知识是必不可少的. 一.COM 是什 ...
- Mybatis框架模糊查询+多条件查询
一.ISmbmsUserDao层 //根据姓名模糊查询 public List<Smbms> getUser(); //多条件查询 public List<Smbms> get ...
- Abp vNext框架 从空项目开始 使用ASP.NET Core Web Application-笔记
参考 Abp vNext框架 从空项目开始 使用ASP.NET Core Web Application http://www.vnfan.com/helinbin/d/745b1e040c9b4f6 ...
- go-gui-控件和信号
go-gui-控件和信号 控件 控件简介 控件是对数据和方法的封装.控件有自己的属性和方法.属性是指控件的特征.方法是指控件的一些简单而可见的功能.如按钮就是一个控件,这个按钮是方形的,里面有张图片, ...
- Java的23种设计模式,详细讲解(二)
本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...
- Clean Code
书名<代码整洁之道> 命名 有意义的命名,使人能读懂 类名和对象名应该是名称或名称短语 方法名应该是动词或动词短语 函数 短小,函数块不要超过一个屏幕 ...