3.4.11 - 函数定义
函数定义的语法为:
functiondef ::= function funcbody
funcbody ::= ‘(’ [parlist] ‘)’ block end
以下是函数定义的简化语法糖:
stat ::= function funcname funcbody
stat ::= local function Name funcbody
funcname ::= Name {‘.’ Name} [‘:’ Name]
语句
lua
function f () body end
会被转化为:
lua
f = function () body end
语句
lua
function t.a.b.c.f () body end
会被转化为:
lua
t.a.b.c.f = function () body end
语句
lua
local function f () body end
会被转化为
lua
local f; f = function () body end
而并非
lua
local f = function () body end
(当函数体内包含f的引用的情况下时,才会凸显此处的差别。)
函数定义是一个可执行的表达式,其值的类型是function。当Lua预编译代码块时,所有的函数体也会被预编译,但是它们还没有被创建。在之后的过程中,当Lua执行到函数定义时,这个函数定义才实例化 instantiated(或者说关闭 closed 了)。此函数实例,或称作闭包(closure),就是这个表达式的最终值。
形参是被作为由参数值进行初始化的局部变量:
parlist ::= namelist [‘,’ ‘...’] | ‘...’
当Lua中的函数被调用时,传入的实参列表都将会被调整到函数形参列表的长度,除非是可变参数函数(variadic function)——参数列表的末尾由三个点('...')表示。一个可变参数函数不会调整其传入的参数列表;相应的,他会收取所有的额外参数并通过*可变参数表达式(vararg expression)*填充到函数中,可变参数表达式也写作三个点('...')。这个表达式的值是一系列额外参数的值,类似于一个具有多个返回值的函数。
作为示例,请考量以下代码:
lua
function f(a, b) end
function g(a, b, ...) end
function r() return 1,2,3 end
接着往下,是传入的参数到形参列表和可变参数列表的对应关系:
CALL PARAMETERS
f(3) a=3, b=nil
f(3, 4) a=3, b=4
f(3, 4, 5) a=3, b=4
f(r(), 10) a=1, b=10
f(r()) a=1, b=2
g(3) a=3, b=nil, ... --> (nothing)
g(3, 4) a=3, b=4, ... --> (nothing)
g(3, 4, 5, 8) a=3, b=4, ... --> 5 8
g(5, r()) a=5, b=1, ... --> 2 3
其结果使用return语句返回(参见3.3.4)。如果在函数的控制范围的末尾一个return语句都没遇到,那么函数将不会返回任何结果。
函数可以返回多少个值与系统相关限制有关,但Lua保证大于1000。
可以用冒号语法模拟定义成员方法,会将一个隐式的额外参数self添加到函数中。因此,语句
lua
function t.a.b.c:f (params) body end
是
lua
t.a.b.c.f = function (self, params) body end
的语法糖。