目录

Lua初探-Expressions下


八、优先级
  • 以下为Lua中的操作优先级,从低到高排列:

     or
     and
     <     >     <=    >=    ~=    ==
     |
     ~
     &
     <<    >>
     ..
     +     -
     *     /     //    %
     unary operators (not   #     -     ~)
     ^
    
  • 通常情况下,你可以使用括号去改变一个表达式的优先级,串联(’..’)和取幂(’^’)运算符是右关联的。所有其他二元运算符都是左关联的。


九、Table Constructors 表构造函数
  • 表构造函数是创建表的表达式。每次创建一个新的表时,表构造函数就会被执行。构造函数可以被使用去创建一个空表或者一个带有一些初始值字段的表。以下为生成语法:

    tableconstructor ::= ‘{’ [fieldlist] ‘}’
      fieldlist ::= field {fieldsep field} [fieldsep]
      field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
      fieldsep ::= ‘,’ | ‘;’
    
  • 形式[exp1] = exp2的每个字段向新表添加一个键为exp1且值为exp2的条目。形式name = exp的字段等同于[“name”] = exp。最后,exp形式的字段等价于[i] = exp,其中i是从1开始的连续整数。其他格式的字段不影响此计数。例如:

     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
    
  • 等价于:

    do
           local t = {}
           t[f(1)] = g
           t[1] = "x"         -- 1st exp
           t[2] = "y"         -- 2nd exp
           t.x = 1            -- t["x"] = 1
           t[3] = f(x)        -- 3rd exp
           t[30] = 23
           t[4] = 45          -- 4th exp
           a = t
         end
    

十、Function Calls 函数调用
  • Lua中的函数调用具有以下语法:

    functioncall ::= prefixexp args
    
  • 在一个函数调用中,第一个prefixexp和参数被执行。如果prefixexp是一个函数类型,会用给予的参数调用该函数。否则prefixexp的call元方法被调用,调用时具有prefixexp的值作为第一个参数,后跟原始调用参数。

  • 格式如下:

    functioncall ::= prefixexp ‘:’ Name args
    
  • v:name(args) 和v.name(v,args)都可以用来调用方法,里面的v只会被执行一次。

  • 参数具有以下语法:

    args ::= ‘(’ [explist] ‘)’
    args ::= tableconstructor
    args ::= LiteralString
    
  • 在调用函数前所有的参数表达式会先进行评估。f {fields}形式的调用是f({fields})的语法糖; 也就是说,参数列表是一个新表。 形式为f’字符串’(或f“字符串”或f [[string]])的调用是f(‘string’)的语法糖; 也就是说,参数列表是单个文字字符串

  • 表单return functioncall的调用称为尾调用。 Lua实现了正确的尾调用(或正确的尾递归):在尾调用中,被调用的函数重用调用函数的堆栈条目。 因此,程序可以执行的嵌套尾调用的数量没有限制。 但是,尾调用会删除有关调用函数的所有调试信息。 请注意,尾调用只发生在特定的语法中,其中返回只有一个函数调用作为参数; 这种语法使调用函数完全返回被调用函数的返回值。 因此,以下示例都不是尾调用:

     return (f(x))        -- results adjusted to 1
     return 2 * f(x)
     return x, f(x)       -- additional results
     f(x); return         -- results discarded
     return x or f(x)     -- results adjusted to 1
    

十一、Function Definitions 函数定义
  • 函数定于语法如下:

    functiondef ::= function funcbody
    funcbody ::= ‘(’ [parlist] ‘)’ block end
    
  • 以下为定义一个简单函数的语法规则:

    stat ::= function funcname funcbody
    stat ::= local function Name funcbody
    funcname ::= Name {‘.’ Name} [‘:’ Name]
    
  • 该声明

     function f () body end
    
  • 会转译为:

    f = function () body end
    
  • 该声明

    function t.a.b.c.f () body end
    
  • 会转译为:

    t.a.b.c.f = function () body end
    
  • 该声明

    local function f () body end
    
  • 会转译为:

    local f; f = function () body end
    
  • 而不是:

    local f = function () body end

  • 函数定义是可执行表达式,其值具有类型函数。 当Lua预编译一个块时,它的所有函数体也都被预编译。 然后,每当Lua执行函数定义时,该函数被实例化(或关闭)。 此函数实例(或闭包)是表达式的最终值。

  • 当一个函数被调用,参数列表会调整为参数列表的长度,除非函数是一个可变参数函数,该参数由参数列表末尾的三个点(’…’)表示。 vararg函数不会调整其参数列表; 相反,它收集所有额外的参数并通过vararg表达式将它们提供给函数,该表达式也写为三个点。 此表达式的值是所有实际额外参数的列表,类似于具有多个结果的函数。 如果在另一个表达式内或表达式列表的中间使用vararg表达式,则将其返回列表调整为一个元素。 如果表达式用作表达式列表的最后一个元素,则不进行任何调整(除非最后一个表达式括在括号中)。

  • 思考如下定义:

     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end
    
  • 然后,我们从参数到参数和vararg表达式有以下映射:

    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