Skip to content

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

的语法糖。