lua学习之深入函数第二篇
深入函数 2
非全局的函数
- 函数是第一类值,函数可以存储到全局变量,局部变量,table 字段中
- lua 函数库中的大部分函数存储到 table 字段中
Lib = {}
Lib.foo = function (x, y)
return x + y
end
Lib.goo = function (x, y)
return x - y
end
Lib = {
foo = function (x, y) return x + y end,
goo = function (x, y) return x - y end
}
Lib = {}
function Lib.foo(x, y) return x + y end
fucntion Lib.goo(x, y) return x - y end
- 将一个函数存储到一个局部变量中,即为「局部函数」
- 该函数只能在对应的作用域使用,对于「程序包」
package很有用 - lua 将每一个程序块当作一个函数来处理
- 在程序块中声明的函数就是局部函数,只在该程序块中可见
- 词法域确保了程序包中的其他函数可以使用这些局部函数。
local f = function (<参数列表>)
<函数体>
end
local g = function (<参数列表>)
<函数代码>
f(实参) -- 可以调用 f
<函数代码>
end
local function f(<参数列表>)
<函数体>
end
-- 阶乘 n! = n * (n - 1) * (n - 2) * ... 1
local fact = function (n) -- 错误的递归函数定义
if n == 0 then
return 1
else
return n * fact(n - 1) -- fact 函数定义未完成,调用的是 fact 全局变量,而不是 fact 函数本身
end
end
-- 正确的递归函数定义
local fact
fact = function (n)
if n == 0 then
return 1
else
return n * fact(n - 1)
end
end
local function foo(<参数>) <函数体> end
-- Lua 将其展开为:
local foo
foo = function (<参数>) <函数体> end
-- 正确的函数定义,对于间接递归无效
local function fact (n)
if n == 0 then
return 1
else
return n * fact(n - 1)
end
end
-- 递归就是函数调用函数本身
-- 间接递归就是 a 函数调用 b 函数而 b 函数又调用了 a 函数
-- 间接递归需要使用明确的前向声明
local f, g
function g ()
<函数代码>
f()
<函数代码>
end
function f() -- 不要加 local 如果加上那么在函数 g 中引用的就处于未定义状态,因为 lua 会创建一个全新的局部变量 f
<函数代码>
g()
<函数代码>
end
正确的尾调用
- 「尾调用」是类似于
goto的函数调用 - 当一个函数调用是另一个函数的最后一个动作时,该调用就是一条「尾调用」
function f (x)
<函数代码>
return g(x)
end
- f 调用完 g 之后就没有执行其他代码了
- 在这种情况下,程序就不需要返回「尾调用」所在的函数了
- 在「尾调用」之后,程序无需保存任何关于该函数的栈信息
- 当 g 返回时,执行控制权可以直接返回调用 f 的那个点上
- 使得在进行「尾调用」时不耗费任何栈空间
- 这种实现称为「尾调用消除」
-- 尾调用函数
function foo(n)
if n > 0 then
return foo(n - 1)
end
end
-- 调用完 g 函数后还进行了加法操作,非尾调用
return g(x) + 1
-- 有 or 操作,必须调整为一个返回值
retrun x or g(x)
-- 函数外嵌套一个括号,强制其只返回一个返回值
return (g(x))
-- 尾调用标准格式
return <func>(<args>)
-- 是一个尾调用
-- 调用前会对 <func> 及其参数求值
return x[i].foo(x[j] + a * b, i + j)
编写状态机
- 典型例子:迷宫
-- 四间房间的迷宫
function room1()
local move = io.read()
if move == "south" then
return room3()
elseif move == "east" then
return room2()
else
print("invalid move")
return room1()
end
end
function room2()
local move = io.read()
if move == "south" then
return room4()
elseif move == "west" then
return room1()
else
print("invalid move")
return room2()
end
end
function room3()
local move = io.read()
if move == "north" then
return room1()
elseif move == "east" then
return room4()
else
print("invalid move")
return room3()
end
end
function room4()
print("congratulations!")
end
- 若没有「尾调用消除」,每次用户移动都会创建一个新的栈层,若干步后可能会栈溢出
- 「尾调用消除」多用户移动的次数没有任何限制
- 因为每次移动实际上只是完成一条
goto语句到另一个函数
lua学习之深入函数第二篇的更多相关文章
- lua学习之深入函数第一篇
深入函数第一篇 函数是第一类值,具有特定的词法域 第一类值 第一类值的意思是函数与 lua 中的其他类型如数字,字符串具有相同的权力 函数可以存储到全局变量或局部变量变量,还可以存储到 table 中 ...
- lua学习之类型与值篇
类型与值 lua 是动态类型的语言 在语言中没有类型定义的语法 每个值都携带有它的类型信息 8种基础类型 用 type 可以返回这个值的类型的名称 将一个变量用于不同类型,通常会导致混乱的代码 但合理 ...
- Python学习之路【第二篇】-pyc简介、Python常用的数据类型及其用法和常用运算符
1.pyc简介 python程序在运行时也有编译过程,编译后会产生.pyc文件.这是一种由python虚拟机执行的二进制文件(字节码),用于保存内存中PyCodeObject,以便加快程序的加载运行. ...
- Lua学习笔记3. 函数可变参数和运算符、转义字符串、数组
1. Lua函数可以接受变长数目的参数,和C语言类似,在函数的参数列表中使用(...)表示函数可以接受变长参数 lua函数将参数存放在一个table中,例如arg,那么#arg可以获得参数的个数 fu ...
- 深入学习jQuery选择器系列第二篇——过滤选择器之子元素选择器
× 目录 [1]通用形式 [2]反向形式 [3]首尾元素 [4]唯一元素 前面的话 在上一篇中已经介绍过基础选择器和层级选择器,本文开始介绍过滤选择器.过滤选择器是jQuery选择器中最为庞大也是最为 ...
- python之函数第二篇
一.名称空间与作用域 名称空间分类: 内置名称空间 import this dir(buil-in) 查看全部内置 全局名称空间 局部名称空间 在函数体内等 查询全局和局部 globals()方法可以 ...
- [知了堂学习笔记]_css3特效第二篇--行走的线条&&置顶导航栏
一.行走的线条. 效果图(加载可能会慢一点儿,请稍等...): html代码: <div class="movingLines"> <img src=" ...
- 马上运行函数-$(function(){})篇
QQ:1187362408 欢迎技术交流和学习 马上运行函数-$(function(){})篇(jquery): TODO: 1.jquery:jQuery(function($){ }) 与 $(d ...
- 学习KnockOut第二篇之Counter
学习KnockOut第二篇之Counter 欲看此 ...
随机推荐
- mysql 用户操作和授权
1.查看mysql的版本 mysql -V 2.用户操作 # 创建用户 create user 'username'@'ip地址' identified by '密码'; # 用户重命名 rename ...
- 5.JavaSE之数据类型详解
数据类型: 强类型语言: 要求变量的使用严格要求符合规定,写错了就不行,所有变量都必须先定义后才能使用,否则是不能使用的. 比如Java.C++都是强类型语言,也就是说,一旦定义了一个变量,只定义了某 ...
- es7中数组如何判断元素是否存在
const arr = [1,2,3,4,5,6] console.log(arr.includes(4)) //true
- Java电商支付系统手把手实现(二) - 数据库表设计的最佳实践
1 数据库设计 1.1 表关系梳理 仔细思考业务关系,得到如下表关系图 1.2 用户表结构 1.3 分类表结构 id=0为根节点,分类其实是树状结构 1.4 商品表结构 注意价格字段的类型为 deci ...
- 在eclipse中导入源码
因为初学java有一个源码项目想要导入,在网上找了很多方法试了都不行,后来发现其实是想多了,这里说一个很简洁的方法.* 1.首先点eclipse中的File然后点import, 2. 然后选Gener ...
- Excel.Application使用手册
Excel.Application组件使用方法,适合应用于使用EXCEL组件做WEB应用开发. 转自http://bbs.xtjc.com/thread-376095-1-1.html 定制模块行为( ...
- cnblogs 美化主题
Silence主题 一个简洁的主题, 不带广告,我很喜欢 cnblogs 域名解析 这需要注意一点是:github.io项目名需要和用户名一致才能正确访问,否则会报404 Markdown格式化编辑 ...
- ASP.Net Core 发布到IIS Http Error 502.5 官方解决办法
Http Error 502.5 - Process Failure 在IIS上发布.NET Core程序出现这个错误.网上搜索到的办法为什么总行不通呢? 有可能年代久远,现在的环境与当年不同,所以解 ...
- 使用dlib自带的面向梯度直方图(HOG)和线性分类器方法来检测人脸
之前使用opencv里面CascadeClassifier(级联分类器)来识别人脸, 下面使用dlib库来实现人脸识别. dlib是一个开源的库,它包含了很多内容有机器学习,图像处理,数值算法等等. ...
- tomcat性能优化梳理
tomcat性能优化 Tomcat本身优化 Tomcat内存优化 启动时告诉JVM我要一块大内存(调优内存是最直接的方式) 我们可以在 tomcat 的启动脚本 catalina.sh 中设置 jav ...