lua函数用法,lua函数库
在Lua中,您可以使用数字和字符串之类的函数。函数可以存储在变量中,存储在表中,作为函数参数传递,以及用作函数的返回值。
在Lua中,函数和其他值一样是匿名的。函数作为一个值存储在变量中。下面的例子是bit 2,可以帮助理解:
a={p=print}
a.p(Hello World) - Hello World
print=math.sin - print 现在指的是sin函数
高级助理(打印(1)) - 0.841470
sin=a.p - sin 现在指的是打印功能
辛(10,20) - 10 20
为函数创建表达式。
函数foo (x)返回2*x end
-实际上,它是:
foo=function (x)返回2*x end
从上面可以看出,function的定义实际上是创建一个 function 类型的值,并将它赋给一个变量。我们可以把function (x) body end看作function的构造函数,就像{}是table的构造函数一样。
表库有一个函数table.sort,它接受一个表,然后对表中的元素进行排序。排序可能有各种规则,如升序、降序、数字或字母顺序、根据表中的键排序等。这个函数不提供各种排序选项,只提供单一选项,即函数的第二个参数,order function,order function,接受两个元素并返回一个布尔值只是决定第一个元素是否出现在第二个元素之前。请看下面的例子:
网络={
{name=grauna ,IP=210.26.30.34},
{ name= arraial ,IP=210.26.30.23},
{name=lua ,IP=210.26.23.12},
{name=derain ,IP=210.26.23.20},
table.sort(网络,函数(a,b) return (a.name b.name) end)
从上面可以看出,匿名函数使用起来很方便。
这里有个概念,高阶函数。它可以将其他函数作为参数。这里有一个例子,导数函数(嘿,我不记得很多年前的事情了,我和我的同事讨论了很久)
函数导数(f,)
=或1e-4
返回函数(x)
返回(f(x)-f(x))/
c=导数(数学.正弦)
print(math.cos(10),c(10))
- -0.83907152907645 -0.83904432662041
在文章的开头,Lua中的函数可以像普通值一样使用,可以存储在全局变量、局部变量和表中。往下看,函数存储在表中,这是一个很优秀的特性,可以实现很多高级功能,比如模块、面向对象等。
1.封闭函数
先看一个例子。有两张表,一张有学生姓名,另一张有年级;每个学生。现在根据学生的年级对前面的表格进行排序。根据您之前所学,您可以使用以下代码:
names={ 彼得,保罗,玛丽 }
分数={玛丽=10,保罗=7,彼得=8}
table.sort(名称,函数(n1,n2)
返回等级[n1]等级[n2] -比较等级
结束)
现在写一个函数来实现这个功能:
函数sortbygrade(名称,等级)
table.sort(名称,函数(n1,n2)
返回等级[n1]等级[n2] -比较等级
结束)
目标
上面代码有趣的地方在于,sort中的匿名函数可以访问参数中的grades,而grades是sortbygrade的一个局部变量。在这个匿名函数中,grades既不是局部变量,也不是全局变量,而是一个非局部变量(IQ有点捉鸡的意思)。
现在我们来看看这个非局部变量的妙用。请看下面的例子:
函数newCounter()
局部i=0
返回函数()-匿名函数
i=i 1
返回I
c1=newCounter()
print(c1()) - 1
print(c1()) - 2
c2=newCounter()
print(c2()) - 1
print(c1()) - 3
print(c2()) - 2
在上面的代码中,匿名函数引用非局部变量I来计数。但是,当调用这个匿名函数时,I不再在有效范围内,因为创建I (newCounter)的函数已经返回。但是Lua可以通过使用封闭函数来正确处理这种情况。简单地说,封闭函数是一个函数加上访问非局部变量所需的所有元素。如果再调用一个newCounter,它会重新创建一个新的非局部变量I,得到一个新的封闭函数。如上例,c1和c2是基于一个函数的两个封闭函数,它们有两个独立的非局部变量I的实例。
封闭函数在许多情况下都很有用。比如在高阶函数中(比如sort),可以作为参数使用;像newCounter一样在自己的函数体中创建其他函数;作为回调函数。一个典型的例子是,在传统的GUI工具箱中,创建按钮,每个按钮都需要一个回调函数来响应按键动作。例如,一个计算器需要10个类似的按钮,每个按钮对应一个数字。您可以使用以下函数创建它:
功能数字按钮(数字)
返回按钮{ label=tostring(digit)、
动作=功能()
添加到显示(数字)
目标
在上面的例子中,我们假设digitButton是一个工具箱函数,用来创建一个按钮。label是按钮的标签,action是回调函数,响应按键操作。这个回调函数可以在digitButton完成工作并且局部变量digit超出作用域很久之后调用,但是它仍然可以访问变量digit。
因为函数存储在公共变量中,所以Lua可以很容易地重定义一些函数,甚至是Lua预定义的函数。看下面这个例子。重新定义sin函数,将参数从原来的弧度改为度数。新函数必须转换参数的值,然后调用原罪函数实现函数。
oldSin=math.sin
math.sin=函数(x)
返回oldSin(x*math.pi/180)
-建议使用以下内容
local oldSin=math.sin
当地k=math.pi/180
math.sin=函数(x)
返回oldSin(x*k)
目标
建议采用第二种实现方式。我们将原始函数保存在一个局部变量中,访问它的唯一方式是通过函数的新版本。通过这种技术,您可以构建一个沙盒安全环境。当你需要运行一些不可信的代码(比如从互联网上收到的代码)时,这种安全环境是必要的。例如,为了严格限制程序可以访问的文件,可以重新定义函数io.open:
做
local oldOpen=io.open
local access_OK=function(文件名,模式)
-这里添加一些代码来限制访问
检查访问
io.open=函数(文件名,模式)
如果access_OK(文件名,模式),则
返回oldOpen(文件名,模式)
其他
返回零,“拒绝访问”
目标
代码如下。重新定义开放函数后,程序不能访问开放函数的无限制版本,只能使用这个限制版本。这样,Lua可以简单灵活地构建一个安全的沙盒环境。
2.非全局函数
Lua中的函数可以存储在全局变量中,也可以存储在表和局部变量中。
大多数Lua库在表中存储函数。下面的例子着重于定义表中函数的方法:
Lib={}
Lib.foo=function (x,y)返回x y end
Lib.goo=function (x,y)返回x - y端
-使用构造函数
Lib={
foo=function (x,y)返回x y end,
goo=function (x,y)返回x - y端
-另一个语法。
Lib={}
函数Lib.foo (x,y)返回x y end
函数Lib.goo (x,y)返回x - y端
当我们在局部变量中存储一个函数时,我们得到的是一个局部函数,它只在给定的范围内有效。这个特性经常在包中使用。您可以在包中定义局部函数。这些函数只在包中可见,包中的其他函数可以调用这些局部函数:
局部f=函数(参数)
身体
局部g=函数(参数)
一些代码
f() - f 在这里是可见的
一些代码
目标
递归函数有一点微妙。看下面两个代码。
局部事实=函数(n)
如果n==0,则返回1
否则返回n * fact(n-1)-bug
-下面这个可以
本地事实
事实=函数(n)
如果n==0,则返回1
否则返回n *事实(n-1)
目标
查看以下局部函数定义的扩展形式:
局部函数foo ( params)体结束
-扩展到
本地foo
foo=函数(params)体结束
所以上面的递归函数也可以写成,注意3中不同的实现方法。
局部函数事实(n)
如果n==0,则返回1
否则返回n *事实(n-1)
目标
然而,上述技术在间接递归函数中效果不佳。请看下面的例子:
局部f,g - forward 声明
函数g()
一些代码
f()
一些代码
-局部f如果这句话放在这里,那么上面的g()就不能引用正确的f函数。
函数f()
一些代码
g()
一些代码
-调用它,并完成上面的代码。
g()
不信你试试把局部f这个句子放在函数g()的定义后面,看看有什么后果。
3.强有力的尾音
程序员知道函数的调用会产生调用栈。但是在Lua中,当然也有一个调用栈。但是尾调用不同于Lua中的其他编程语言。我们先通过几行代码来看看tailor call是什么。
函数f (x)返回g(x)结束
函数foo (n)
如果n 0,那么
返回foo(n - 1)
-以下都不是。
函数f (x)
g(x) -在调用g之后,f仍然必须在返回之前丢弃来自g的偶然结果
函数f (x)
返回g(x) 1 -必须做加法
函数f (x)
return x或g(x) -必须调整到1个结果
函数f (x)
return (g(x)) -必须调整到1个结果
目标
在Lua中,只有return func(args)格式的调用才是尾调用。即使func和args是复杂表达式也没关系,因为Lua在调用它们之前会计算它们的值。所以下面也是尾叫。
返回x[i]。foo(x[j] a*b,i j)
下面就为这一行envy代码谈谈Lua中尾部调用处理的强大之处。
函数f (x)返回g(x)结束
Lua如何处理尾部调用?和C语言一样,在上面的代码中,F调用G后,G执行后会返回调用G的地方。然而,在Lua中,这是一个尾调用。G执行后会直接返回f的被调用处,这样可以节省大量的堆栈空间。所以像下面这个函数,n太大就不用担心溢出了。
在Lua中,尾调用的一个很好的应用是状态机。你可以用一个函数来表示一个状态,改变状态意味着跳转到一个指定的函数。下面我们用一个简单的迷宫程序例子:迷宫里有几个房间(我们这里有四个),每个房间有四个门,分别通向东、南、西、北。每走一步,玩家指定一个移动方向。如果这个方向有门,那就进对房间;否则,程序给出警告;目标是从起始房间走到目标房间。
这个程序是一个典型的状态机。状态是当前房间,每个房间写一个函数。使用尾呼从一个房间移动到另一个房间。不使用尾呼的话,每次移动都要升级一级栈。移动一定次数后,程序可能会溢出。如果使用尾调用,就不需要担心这个问题。废话少说,下面是代码,已经验证过了,比较简单。
功能室1()
local move=io.read()
如果move==south 则返回room3()
elseif move==east 然后返回room2()
其他
打印(“无效移动”)
返回房间1() -待在同一房间
功能室2()
local move=io.read()
如果move==south 则返回room4()
elseif move==west 然后返回room1()
其他
打印(“无效移动”)
返回房间2()
功能室3()
local move=io.read()
如果move==north ,则返回room1()
elseif move==east 然后返回room4()
其他
打印(“无效移动”)
返回房间3()
功能室4()
打印(“祝贺你!”)
——写完以上四个房间,就给他们打电话。
房间1()
水平有限。如果有朋友发现错误,请留言交流。