Skip to content

3.4.10 - 函数调用

函数调用的语法如下:

functioncall ::= prefixexp args

在函数调用中,首先会计算打头的前缀表达式(prefixexp)和后边的参数(args)。如果前缀表达式的值是function类型的,那么这个值对应的函数就通过所给参数来调用。否则,如果前缀表达式其值有__call元函数的话,会这样调用此元函数:第一个参数是前缀表达式的值,后跟原本的调用参数(参见2.4)。

functioncall ::= prefixexp ‘:’ Name args

这种形式被用来调用成员函数。v:name(args) 其实是 v.name(v, args) 的语法糖,不同之处在于v只被计算一次。

调用参数的语法如下:

args ::= ‘(’ [explist] ‘)’
args ::= tableconstructor
args ::= LiteralString

所有参数表达式会在调用之前被计算。f{fields}调用形式其实就是f({fields})的语法糖;即此参数列表是一个表。 f'string'(或者 f"string" 有或者 f[[string]])调用形式其实就是 f('string')的语法糖;即此参数列表是一个字符串。

所有在非待关闭变量的作用域下的 return functioncall 调用形式被称为尾调用(tail call)。Lua实现了尾调用优化 proper tail calls(或称为尾递归优化 proper tail recursion):在尾部调用中的调用函数会重复使用调用栈。因此程序可以执行无限制的内嵌尾调用。然而,尾调用会擦除所有其调用函数的调试信息。注意尾调用只发生于特定的语法中:return语句只有一个函数调用作为其参数,且这个函数在任何待关闭变量的作用域之外。此语法使得调用函数时直接返回其函数的返回值,其中没有任何多余动作。所以,以下都不是尾调用:

lua
return (f(x))        -- 返回值后还有一步操作,非直接的函数调用
return 2 * f(x)      -- 返回值后有两步操作,也是非直接的函数调用
return x, f(x)       -- 多个返回值
f(x); return         -- 返回值被全局丢弃
return x or f(x)     -- 计算返回值前还有一步操作,非直接的函数调用