码迷,mamicode.com
首页 > 其他好文 > 详细

Lua4.0 参考手册(三)4.5

时间:2014-11-04 15:26:04      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:io   ar   使用   sp   on   cti   bs   工作   tt   

(接上篇)
-------------------
4.5 表达式
-------------------
---------
4.5.1 基本表达式
---------
Lua 中基本表达式是:
    exp ::= `(‘ exp `)‘
    exp ::= nil
    exp ::= number
    exp ::= literal
    exp ::= var
    exp ::= upvalue
    exp ::= function
    exp ::= functioncall
    exp ::= tableconstructor
数值(数值常量)和字符串常量在 4.1 节解释过了。变量在 4.4.2 节解释过了。upvalue 在 4.6 节解释。函数定义在 4.5.9 节解释。函数调用在 4.5.8 节解释。表的构造函数在 4.5.7 节解释。

一个全局变量 x 的调用等价于调用 getglobal("x"),一个下标变量 t[i] 等价于 gettable_event(t,i) 。这些函数的解释参见 4.8 节(getglobal 在基础的库中,gettable_event 仅用于解释目的)。

非终结的 exp1 被用来指示一个表达式的返回值必须被调整为一个值:
    exp1 ::= exp

---------
4.5.2 算术运算符
---------
Lua 支持常见的算术运算符。这些运算符是二元操作符 +(加), -(减), *(乘), /(除) 和 ^(幂),一元操作符 -(负)。如果操作数是数值,或者是可以转化为数值的字符串(根据 4.2 节中给出的规则),所有的操作(除了幂操作)具有通常意义。否则,一个适用的标签函数(参见 4.8 节)将会被调用。幂操作将一直调用一个标签函数。标准的数学库以预想的意义重定义了幂操作(参见 6.3 节)。

---------
4.5.3 关系运算符
---------
Lua 中的关系运算符是:
    == ~= < > <= >=
他们返回 nil 做为假,非 nil 做为真。

相等(==)首先比较两个操作数的标签。如果不同,结果为 nil。否则,比较它们的值。数值或字符串以常见的方式比较。表, userdata 和函数按引用比较,也就是说,两个比较的表只有是同一个的时候才被认为是相等的。不等运算 ~= 和相等运算 (==) 具有完全相反的结果。

4.2 节的转换规则不适用于相等比较。所以,"0"==0 的求值结果为 false,t[0] 和 t["0"] 表示表中不同的元素。

顺序比较操作符是这么工作的:如果两个参数都是数值,他们就以数值比较。如果两个参数都可以转化为字符串,它们将以字典序比较。否则的话, 标签方法 "lt" 将被调用(参见 4.8 节)。

---------
4.5.4 逻辑运算符
---------
Lua 中的逻辑运算符是:
    and or not
和控制结构一样,所有的逻辑运算符认为 nil 为假而其它的都为真。
合取运算符 and 返回 nil 如果它的第一个参数为 nil;否则,它返回它的第二个参数。析取运算符 or 返回它的第一个参数如果它不同于 nil;否则,它返回它的第第二个参数。and 和 or 是短路求值,也就是说,第二个操作数只在需要的时候才被求值。

有两个使用逻辑运算符的习惯用法。第一个是:
    x = x or v
它等价于
    if x == nil then x = v end
该用法当 x 未设置时给 x 设置一个默认值。
第二个习惯用法是:
    x = a and b or c
它应该被读为 x = (a and b) or c. 它等价于
    if a then x = b else x = c end
条件是 b 不为 nil。

---------
4.5.5 连接
---------
Lua 中的字符串连接操作符由两点“.." 表示。如果两个操作数是字符串或者数字,他们按 4.2 节的规则转化为字符串。否则,标签方法 "concat" 将被调用(参见 4.8 节)。

---------
4.5.6 优先级
---------
运算符的优先级如下表所示,从低到高排列:
    and or
    < > <= >= ~= ==
    ..
    + -
    * /
    not - (unary)
    ^
所有的二元操作符具体左结合性,^除外,幂操作具有右结合性。预编译可能重新排列相关运算符(比如 .. 和 +)的求值顺序,只要优化不改变正常的结果。反而,这些优化可能改变一些结果,如果你为这些运算符定义了一些不相关的标签方法。

---------
4.5.7 表的构造函数
---------
Table 的构造函数是创建表的表达式。当对构造函数求值的时候,会生成一个新的表。构造函数可以用来新建一个空表,或者新建一个表并初始化一些字段。
构造函数的语法如下:
    tableconstructor ::= `{‘ fieldlist `}‘
    fieldlist ::= lfieldlist | ffieldlist | lfieldlist `;‘ ffieldlist | ffieldlist `;‘ lfieldlist
    lfieldlist ::= [lfieldlist1]
    ffieldlist ::= [ffieldlist1]

lfieldlist1 被用来初始化列表。
    lfieldlist1 ::= exp {`,‘ exp} [`,‘]

列表中的表达式被赋值给一个连续的数值索引,索引从 1 开始。例如:
    a = {"v1", "v2", 34}
等同于:
    do
      local temp = {}
      temp[1] = "v1"
      temp[2] = "v2"
      temp[3] = 34
      a = temp
   end

ffieldlist1 初始化表中的其它字段:
    ffieldlist1 ::= ffield {`,‘ ffield} [`,‘]
    ffield ::= `[‘ exp `]‘ `=‘ exp | name `=‘ exp
例如:
    a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}
等同于:
    do
      local temp = {}
      temp[f(k)] = g(y)
      temp.x = 1 -- or temp["x"] = 1
      temp.y = 3 -- or temp["y"] = 3
      temp[0] = b+c
      a = temp
    end

事实上, {x = 1, y = 4} 这样的表达式是表达式 {["x"] = 1, ["y"] = 4} 的语法糖。

两种形式都可以有一个可选的结尾逗号,并且在同样的构造中可以用分号分割。例如,下面的形式都是对的。
    x = {;}
    x = {"a", "b",}
    x = {type="list"; "a", "b"}
    x = {f(0), f(1), f(2),; n=3,}

---------
4.5.8 函数调用
---------
Lua 中的函数调用有如下语法:
    functioncall ::= varorfunc args
首先,varorfunc 被求值。如果它的值类型为 function,这个函数就用给定的参数被调用。 否则,标签方法 "function" 被调用,第一个参数为 varorfunc  的值,之后是原来的调用参数(参见 4.8 节)。

形如:
    functioncall ::= varorfunc `:‘ name args
可被用来调用 "methods"。v:name(...) 调用是 v.name(v, ...) 的语法糖,除了 v 只被求值一次。

参数的语法如下:
    args ::= `(‘ [explist1] `)‘
    args ::= tableconstructor
    args ::= literal
    explist1 ::= {exp1 `,‘} exp

所有参数表达式在函数调用前被求值。f{...} 调用是 f({...}) 的语法糖,即,参数列表是一个新建的 table。f‘...‘ (或者 f"..." 或者 f[[...]])调用是 f(‘...‘) 的语法糖,即,参数列表是一个字符串常量。

因为一个函数可以返回任意多个值(参见 4.4.3 节),返回值的个数在使用之前必须进行调整(参见 4.3 节)。如果一个函数调用作为语句使用(参见 4.4.5 节),它的返回结果会被调整到 0 个,因而返回值被全部丢弃。如果一个函数在需要一个值(语法中被表示为非终结的 exp1)的地方调用,它的返回结果会被调整到 1 个,因而除了第一个返回值其它的都被丢弃。如果一个函数在需要多个值的地方调用(语法上表示为非终结的 exp),不对返回结果个数进行调整。唯一可以保持多个值的地方是赋值的最后(或唯一)一个表达式,参数列表中,或者在 return 语句中。这里是一些例子:
    f() -- 调整到 0 个返回值
    g(f(), x) -- f() 调整到 1 个返回值
    g(x, f()) -- g 获得 x 和 f() 的所有返回值
    a,b,c = f(), x -- f() 调整到 1 个返回值 ( c 获得 nil )
    a,b,c = x, f() -- f() 调整到 2 个返回值
    a,b,c = f() -- f() 调整到 3 个返回值
    return f() -- 返回所有的 f() 的返回值
    return x,y,f() -- 返回 a, b, 和所有的 f() 的返回值

-------------------
4.5.9 函数定义
-------------------
函数定义的语法是:
    function ::= function `(‘ [parlist1] `)‘ block end
    stat ::= function funcname `(‘ [parlist1] `)‘ block end
    funcname ::= name | name `.‘ name | name `:‘ name

语句
    function f () ... end

    f = function () ... end
的语法糖。
语句
    function v.f () ... end

    v.f = function () ... end
的语法糖。

一个函数定义是一个可执行的表达式,它的值类型为 function。当 Lua 预编译一个 chunk,它所有的函数体也都会被预编译。然后,当 Lua 执行函数定义,它的 upvalue 就是确定的了(参见 4.6 节),函数也就实例化(或者闭合)了。这个函数实例(或者闭包)就是表达式的最终值。同样函数的不同实例可能有不同的 upvalue 。

参数和局部变量的表现一样,由参数值进行初始化。
    parlist1 ::= `...‘
    parlist1 ::= name {`,‘ name} [`,‘ `...‘]
当一个函数被调用时,实参的个数被调整为和形参一样(参见 4.3 节),除非函数是可变参数函数(vararg function),也就是参数列表的最后是三个点(‘...‘)。一个可变参数函数不需要调整它的实参列表;而是把所有额外的实参收集到名为 arg 的隐含参数中。arg 的值是一个表,它的一个字段 n 表示额外参数的个数,并且额外的参数位于 1, 2, ..., n 。

作为一个例子,考虑下面的定义:
    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, arg={n=0}
  g(3, 4)    a=3, b=4, arg={n=0}
  g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2}
  g(5, r()) a=5, b=1, arg={2, 3; n=2}

结果由 return 语句返回(见 4.4.3节)。如果执行到函数最后也没有 return 指令的话,函数不返回值。

语法
    funcname ::= name `:‘ name
用来定义函数,函数有一个隐含的参数 self。

语句
    function v:f (...) ... end
只是
    v.f = function (self, ...) ... end
的语法糖。
注意函数获得一个额外的名为 self 的形式参数。
(未完待续)

Lua4.0 参考手册(三)4.5

标签:io   ar   使用   sp   on   cti   bs   工作   tt   

原文地址:http://my.oschina.net/xhan/blog/340512

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!