函数可以完成2件事,完成工作
或者计算并返回结果
。
函数语法
function func_name (arguments-list)
statements-list
end
Ps:Lua 使用的函数可以是 Lua 编写也可以是其他语言编写,对于 Lua 程序员来说用什
么语言实现的函数使用起来都一样。
function Show(a)
print(a)
end
Show(100)
返回多个值
在 lua 中函数可以返回多个值,例如 string.find,其返回匹配串 “开始和结束的下标”
(如果不存在匹配串返回 nil)。
s, e = string.find("hello Lua users", "Lua")
print(s, e) --> 7 9
计算最大值和最大值的索引
function MaxM(arr) | |
local maxIndex=1 | |
local max=arr[maxIndex] | |
for key, value in pairs(arr) do | |
if value>max then | |
maxIndex=key | |
max=value | |
end | |
end | |
return max,maxIndex | |
end | |
local max,maxIndex=MaxM({1.5,6,7,9}) | |
print('最大值和索引为:'..max..' '..maxIndex) |
返回函数
如return fac()
这样的形式就是返回函数,其意义是执行 fac 函数并返回 fac 的返回值,若没有返回 nil。
可变参数
unpack
unpack
,接受一个数组作为输入参数,返回数组的所有元素。
f = string.find
a = {"hello", "ll"}
print(f(unpack(a))) --> 3 4
...可变参数
可以使用… 表示不明确数量的可变参数,在使用时在函数中以表的形式获取。
function Sum(a,b,c,...)
local arg={...} --将可变参数存储到arg表中
for key, value in pairs(arg) do
print(value) -- 9 7 4 10
end
end
Sum(5,4,8,9,7,4,10)
使用命名参数
由于 lua 使用弱类型的缘故,我们可以像这样使用命名参数,在这种情况下调用函数可以写为函数名 {参数}
的形式。
function Show(arg)
print(arg.name..' '..arg.title)
end
Show{name='小屋',title='学习lua'}
深入理解函数
Lua 中的函数是带有词法定界(lexical scoping)的第一类值(first-class values)。
第一类值指:在 Lua 中函数和其他值(数值、字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值。
词法定界指:被嵌套的函数可以访问他外部函数中的变量。这一特性给 Lua 提供了强大的编程能力。
匿名函数
得益于上面的第一条规则,其实我们声明函数,本是 fac=function(arg) body end
。
这个语句创建了一个匿名函数,并把这个函数赋值为 fac,我们就可以称这个函数为 fac 了。
在table.sort()
函数中使用匿名函数:
在函数中接收 2 个参数,第一个参数接收一个表,第二个参数接收一个比较函数。
arr={
{name='A',age=16},
{name='B',age=20},
{name='C',age=9},
}
table.sort(arr,function (a,b)
return a.age>b.age
end)
for key, value in pairs(arr) do
for k, v in pairs(value) do
print(k,v)
end
end
以其他函数作为参数的函数在 Lua 中被称作高级函数,高级函数在 Lua 中并没有特
权,只是 Lua 把函数当作第一类函数处理的一个简单的结果。
闭包
当一个函数内容嵌套另一个函数时,被嵌套的匿名函数还可以访问第一函数中的参数,这就被称为闭包;事实上仅有很少的语言支持这样的特性。
来看看下面这个例子:
function NewCount()
local i=0
return function ()
i=i+1
return i
end
end
在匿名函数中,我们依然可以直接正确的访问 i。
现在,假如我们这样调用这个函数结果是怎样呢?
local c1=NewCount()
local c2=NewCount()
print(c1())
print(c1())
print(c2())
print(c1())
!{函数闭包}(https://i.loli.net/2020/02/02/r2ftpGPjsVlmqyg.png)
可以发现,函数的结果并非我们的预期,在第一函数体中的 i 的值可以被保留下来,而且 c1 和 c2 的保存值并不相同,这就是闭包。
Ps:我们把这个 i 称为外部的局部变量或者 upvalue。
简单的说闭包是一个函数加上它可以正确访问的 upvalues。如果我们再次调用 newCounter,将创建一个新的局部变量 i,因此我们得到了一个作用在新的变量 i 上的新闭包。
分析:c1 和 c2 是作用同一个局部变量上的不同实例上的两个闭包。
使用闭包重写函数
闭包在完全不同的上下文中也是很有用途的。因为函数被存储在普通的变量内我们
可以很方便的重定义或者预定义函数。通常当你需要原始函数有一个新的实现时可以重
定义函数。例如你可以重定义 sin 使其接受一个度数而不是弧度作为参数:
local oldSin=math.sin
math.sin=function (x)
return oldSin(x*math.pi/180)
end
通过这个特性我们可以对原函数进行修改,在某些时刻可以构建运行危险代码的沙盘。
局部函数
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
function Lib.goo(x,y)
return x-y
end
Ps:在使用递归函数时,要注意要先声明函数在调用。
尾调用
尾调用是一种类似在函数结尾的 goto 调用,当函数最后一个动作是调用另外一个函
数时,我们称这种调用尾调用。
Ps:Lua 中尾调用不消耗栈空间,由于尾调用不需要使用栈空间,那么尾调用递归的层次可以无限制的