函数语法:
function func_name(arguments-list)
statements-list
end
函数通常由若干语句或者表达式组成,在 Lua 中,函数是抽象化语句或者表达式的一种重要机制。是对函数有两种用途:
- 完成指定的任务,这种情况下函数被作为调用语句。在某些其他语言中,这类函数也被成为过程或子程序;
- 计算并返回值,这种情况下函数被作为表达式。
无论是上述哪种情况,我们都将函数的参数列表写在一对圆括号内。如果函数的参数列表为空,则必须使用一对空圆括号表明是函数调用。
print(8 * 9, 9 / 8)
a = sin(3) + cos(10)
print(date())
上述规则有一个例外情况,当函数只有一个参数,且这个参数是字符串或者表构造器的时候,圆括号可以省略:
print "Hello World" | <--> | print("Hello World") | dofile 'a.lua' | <--> | dofile ('a.lua') | print [[a multi-line message]] | <--> | print([[a multi-line message]]) | f{x = 10, y = 20} | <--> | f({x = 10, y = 20}) | type{} | <--> | type({}) | 实际案例:function f(a)
print(a.x, a.y)
end
f{x = 10, y = 20} -- 省略圆括号
Lua 也为面向对象方式的函数调用提供了特殊的语法,表达式 o:foo(x)与 o.foo(o, x)是等价的,后面的章节会详细介绍面向对象内容。
一个Lua程序既可以条用Lua语言编写的函数,也可以调用C语言(或者宿主程序使用的其他任意语言)编写的函数。一般来说,我们选择使用C语言编写的函数来实现对性能要求更高,或不容易直接通过Lua语言进行操作的操作系统机制等。例如,Lua语言标准库中所有的函数就都是使用C语言编写的。不过,无论一个函数是用Lua语言编写的还是用C语言编写的,在调用它们时都没有任何区别。
Lua 函数中的实参形参匹配与赋值语句中的变量值匹配类似,多余部分被忽略,缺少部分用空值(nil)补足:
function f(a, b)
return a or b
end
--调用 参数
f(3) a = 3, b = nil
f(3, 4) a = 3, b = 4
f(3, 4, 5) a = 3, b = 4 (5 is discarded)
尽管这种匹配模式会导致程序错误,但是它同样也是非常有用的,尤其是对于参数的默认值而言。
参看下列函数,它将一个全局计数器累加:
function incCount(n)
n = n or 1
count = count + n
end
该函数指定 1 为其参数的默认值,也就是说,无参调用 incCount()将会令 count 加 1。当你调用incCount()函数, Lua 首先将参数 n 初始化为空值,然后将其与 or 的第二个操作数,也就是 1 的计算结果作为默认值赋给 n。
5.1 多返回值
Lua语言中一种与众不同但非常有用的特性是允许一个函数返回多个结果(Multiple Results)。Lua语言中几个预设函数就会返回多个值。我们接触过函数strfind,该函数用于在字符串中定位模式(pattern)。当找到了对应的模式时,该函数会返回两个索引值:所匹配模式在字符串中起始字符和结尾字符的索引。使用多重赋值(multiple assignment)可以同时获取到这两个结果:
s, e = strfind("hello Lua users", "Lua")
print(s, e) --> 7 9
Lua语言编写的函数同样可以返回多个结果,只需在return关键词后列出所有要返回的值即可。例如,一个用于查找序列中最大元素的函数可以同时返回最大值及该元素的位置:
function maximum(a)
local mi = 1 -- 最大值的索引
local m = a[mi] -- 最大值
for i, val in a do
if val > m then
mi = i
m = val
end
end
return m, mi --返回最大值及其索引
end
print(maximum({8,10,23,12,5})) --> 23 3
Lua语言根据函数的被调用情况调整返回值的数量。当函数被作为一条单独语句调用时,其所有返回值都会被丢弃;当函数被作为表达式(例如,加法的操作数)调用时,将只保留函数的第一个返回值。只有当函数调用是一系列表达式中的最后一个表达式(或是唯一一个表达式)时,其所有的返回值才能被获取到。这里所谓的“一系列表达式”在Lua中表现为4种情况:多重赋值、函数调用时传入的实参列表、表构造器和return语句。为了分别展示这几种情况,接下来举几个例子:
function foo0() end -- 不返回结果
function foo1() return 'a' end -- 返回1个结果
function foo2() return 'a', 'b' end -- 返回2个结果
第一,多重赋值。有以下几种情况:
1、当函数作为最后的或唯一的右值表达式,它将返回尽量多的返回值:
x, y = foo2() -- x = 'a', y = 'b'
x = foo2() -- x = 'a', 'b' 被丢弃
x, y, z = 10, foo2() -- x = 10, y = 'a', z = 'b'
2、如果函数的返回值不够,它将返回空值(nil)来补足:
x, y = foo0() -- x = nil, y = nil
x, y = foo1() -- x = 'a', y = nil
x, y, z = foo2() -- x = 'a', y = 'b', z = nil
3、如果函数不是最后的或唯一的右值表达式,它只返回一个返回值:
x, y = foo2(), 20 -- x = 'a', y = 20 ('b'被丢弃)
x, y = foo0(), 20, 30 -- x = 'nil', y = 20 (30 被丢弃)
第二,当一个函数调用是另一个函数调用的最后一个(或者是唯一)实参时,第一个函数所有返回值都会被作为实参传给第二个函数,我们已经见过很多这样的代码结构,例如函数print。由于函数print能够接受可变数量的参数,所以print(g())会打印出g返回的所有结果。
print(foo0()) --> 没有结果
print(foo1()) --> a
print(foo2()) --> a b
print(1,foo2()) --> 1 a
print( "x" .. foo2() ) --> xab
print(foo2(), 1) --> a 1
print(foo2() .. "x") --> ax (见下说明)
当在表达式中调用foo2时,Lua语言会把其返回值的个数调整为1。因此,在上例的最后一行,只有第一个返回值“a”参与了字符串连接操作。
当我们调用f(g())时,如果f的参数是固定的,那么Lua语言会把g返回值的个数调整成与f的参数个数一致。这并非巧合,实际上这正是多重赋值的逻辑。
第三,LUA5.0以上版本的 表构造器。与多重赋值一样,当函数为构造器中最后的或唯一的元素时,构造器接受函数所有的返回值:
a = {foo0()} -- a = {} --(一个空表)
a = {foo1()} -- a = {'a'}
a = {foo2()} -- a = {'a', 'b'}
在LUA4.0.1中,会把其返回值个数调整为1:
a = {foo0()} -- a = {} --(一个空表)
a = {foo1()} -- a = {'a'}
a = {foo2()} -- a = {'a'} --('b'被丢弃)
第四, return 语句。 return f()将返回 f 函数所有的返回值:
function foo(i)
if i == 0 then
return foo0()
elseif i == 1 then
return foo1()
elseif i == 2 then
return foo2()
end
end
print(foo(1)) --> a
print(foo(2)) --> a b
print(foo(0)) -- (无返回值)
print(foo(3)) -- (无返回值)
我们可以强制一个函数只返回一个返回值,而只需要将返回值列表用圆括号括起来(LUA5.0以上特性,LUA4.0.1是否有括号都是一样的结果):
print((foo0())) --> nil
print((foo1())) --> a
print((foo2())) --> a
|