Lua学习笔记(5)——深入函数

1.函数是一种“第一类值”,他们具有特定的词法域。

2.第一类值,表示Lua中函数与其他类型的值(例如数字)具有相同的权利,函数可以存储到变量或table中,也可以作为实参,还可以作为其他函数的返回值。

3.词法域,是指一个函数可以嵌套在另一个函数中,内部函数可以访问外部函数的变量。

4.函数与其他值一样都是匿名的。即,一个函数名(如print)是一个持有某函数的变量,与其他变量持有各种值的道理是一样的。

函数是匿名的

5.function foo(x) return 2*x end 只是所谓的“语法糖”,是 foo = function(x) return 2*x end 的简化书写形式。此时,表达式“funcrion(x) <body> end”相当于函数的构造式,结果为一个“匿名函数”。

匿名函数

6.接受另一个函数作为实参的函数(例如sort),称为“高阶函数(higher-order function)”。高阶函数是一种强大的编程机制,应用匿名函数来创建高阶函数所需的实参则可以带来更大的灵活性。

闭合函数(closure)

假设有一个学生姓名的表和一个对应名称的年级表
根据学生的年级来对姓名排序

1.上例中,传递给sort的匿名函数可以访问参数grades,而grades是外部函数sortbygrade的局部变量(参数也是一种局部变量)。在这个匿名函数内部,grades既不是全局变量也不是局部变量,将其称为一个“非局部的变量(non-local variable 或 upvalue)”。

2.一个闭合函数就是一个函数加上该函数所需访问的所有“非局部的变量”。从技术上来说,Lua中只有闭合函数,因为函数本身就是一种特殊的closure(即没有非局部变量的closure)。

3.closure结构通常涉及两个函数:closure本身和用于创建该closure的工厂函数。

4.closure对于回调函数很有用。

colsure在回调中的使用

5.closure还可用于重新定义某些函数。

重新定义sin
将老版sin存到私有变量后,只有通过新版本的sin才能访问它

6.利用closure创建沙盒(sandbox),即一个安全的运行环境。

限制程序访问文件(经过重新定义后,程序只能通过受限版本的os.open函数来调用原有的函数,通过将不安全的版本保存到closure的一个私有变量中,从而使得外部再也无法直接访问到原来的版本)

非全局函数(non-global function)

1.只要将一个函数存储到一个局部变量中,即得到了一个“局部函数”,也就是说该函数只能在某个特定的作用域中使用。

词法域确保程序包中的其他函数可以使用局部函数

2.对于局部函数的定义,Lua还支持一种特殊的“语法糖”:

局部函数定义
上述语法糖展开

3.在定义递归的局部函数时,需要特别注意:

递归中的局部函数
上述递归函数的简化

4.间接递归中,必须使用一个明确的前向声明(forward declaration):

间接递归

正确的尾调用(proper tail call)

1.尾调用(tail call),一个函数调用是另一个函数的最后一个调用动作,该调用就称为“尾调用”。判断一个调用是不是尾调用的准则是“一个函数在调用完另一个函数之后,是否就无事可做”。即“return <func>(<args>)”这样的调用形式。

对g的调用就是尾调用
f调用完g之后还需丢弃g的返回值,所以不算尾调用
不是尾调用
在调用前会对参数求值,所以它们可以是任意复杂的表达式

2.尾调用消除(tail-call elimination),尾调用后,函数就无事可做了,因此程序就不需要保存任何关于该函数的栈信息,执行控制权在g返回时,直接返回到f中调用的点上。这使得在进行尾调用时不耗费任何栈空间。

3.由于尾调用不耗费栈空间,所以一个程序可以拥有无数嵌套的尾调用: 

n为任何数字时,都不会造成栈溢出

4.尾调用的一大应用就是编写“状态机”。

5.举一个简单的迷宫游戏例子:一个迷宫有几间房间,每个房间中有东南西北4扇门,用户在每一步移动中都需输入一个移动的方向。如果某个方向上有门,那么用户可以进入对应的房间,不然,程序就打印一条警告。游戏的目标是让用户从最初的房间走到最终的房间。

当前房间就是一个状态,将每间房间都实现为一个函数,并使用尾调用来实现从一间房间移动到另一间房间。使用尾调用对用户的移动次数没有任何限制。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 1.1程序块:Lua执行的每段代码,例如一个源代码文件或者交互模式中输入的一行代码,都称为一个程序块 1.2注释:...
    c_xiaoqiang阅读 2,585评论 0 9
  • 第一篇 语言 第0章 序言 Lua仅让你用少量的代码解决关键问题。 Lua所提供的机制是C不擅长的:高级语言,动态...
    testfor阅读 2,631评论 1 7
  • 原文链接:https://github.com/EasyKotlin 值就是函数,函数就是值。所有函数都消费函数,...
    JackChen1024阅读 5,922评论 1 17
  • 闭上书之后,我想起了《中国合伙人》里的那句台词:“美国人民需要我!” 需要么?不一定,但最起码不会是必需。这句话就...
    頁時弎未阅读 321评论 2 2
  • 撰文:栀子清晨 这是心灵自由30天写作群第六篇 今年我觉知到了自己的课题,但心有恐惧,过不好当下,做不出决定...
    栀子清晨阅读 234评论 4 1