Lua基础 表达式

Lua基础 表达式

在Lua中,表达式包括:数值常量、字符串字面值、变量、单目和双目运算函数调用,也包括一些非传统的函数定义表结构


1.算术运算符

Lua支持常规的算术运算符:'+', '-', '*', '/', '^', '%', '-'(负)。所有这些运算符都对实数起作用。举个例子,x^0.5, 计算x的平方根, x^(-1/3),计算x的立方根的反数。


在Lua中,'%'运算符定义规则如下:

a%b == a - floor(a/b)*b a%b得到的值一定是正的,lua用%进行运算,余数非零,就是非负。所以取余想得到正常的结果用math.fmod(被除数,除数)

对整型参数来说,它表示常规的意义,结果跟第二个参数b符号相同。

对实数来说,它有一些额外的用途。例如,x%1 表示x的小数部分,x-x%1 表示x的整数部分。类似的,x-x%0.01 将x精确到小数点后2位。



2.关系操作

Lua提供了如下关系操作符:

< > <= >= == ~=

所有这些操作符产生的结果都是true或者false


'=='检查是否相等,'~='检查是否不等。这两个操作符可以作用于任意的两个值。如果要比较的两个值是不同的类型,那么Lua认为它们是不等的。否则,Lua根据它们的类型来比较它们是否相等。特例,nil只等于它本身。(先比较类型,然后再根据类型比较值)


Lua根据引用来比较table, userdata, function,也就是说,只有二者是同一个对象的时候,它们才相等。例如:

[plain] view plain copy

  1. a = {}; a.x = 1; a.y = 0
  2. b = {}; b.x = 1; b.y = 0
  3. c = a

执行下上面的代码,你可以得到, a == c, 但是 a ~= b



我们把<, >, <=, >=称为order operator。

order operator只能应用于数值和字符串。Lua根据字母表顺序来比较字符串的大小,字母表的顺序由本地设置决定。非数值和字符串的值只能比较相等或者不相等,不能用于order operator。


当比较两个不同类型的值时,一定要小心:记住"0"和0是不同的。除此以外,2<15显然是true的,但是"2"<"15"是false的(根据字母表顺序比较)。为了避免不一致的结果,当你将string和number混合使用到order operator时,例如 2<"15",Lua会产生一个runtime error。



3.逻辑运算符

逻辑运算符有:and, or, not。跟控制结构(if,while等)类似,所有的逻辑操作符把false和nil认为是false,其他的任意值都为true。

and:如果第一个参数为false,返回第一个参数,否则返回第二个参数。

or :如果第一个参数为false,返回第二个参数,否则返回第一个参数。

[plain] view plain copy

  1. print(4 and 5) ----> 5
  2. print(nil and 13) ----> nil
  3. print(false and 13) ----> false
  4. print(4 or 5) ----> 4
  5. print(false or 5) ----> 5


'and'和'or'都是用short-cut计算方式,也即是说,只有在有需要的时候,才会去计算第二个参数的值。这样保证了类似(type(v)=="table" and v.tag=="h1")这样的表达式不会产生run-time error。(当v不是table类型时,Lua不会去计算v.tag的值)。

"短路求值",又称最小求值,是一种逻辑运算符的求值策略。有当第一个运算值无法确定逻辑运算的结果,才去对第二个运算数进行求值。

有用的Lua表达式:x = x or v,等价于:

if not x then x = v end

(加上x没有被赋值为false),如果x没有被设置,那么给它个默认值v。


另一个有用的Lua表达式:a and b or c,等价于C表达式 a ? b : c,(假设b不为false)。例如,我们可以用下面的语句来得到x和y的最大值。

max = (x >y) and x or y

当 x>y,第一个and表达式结果为第二个参数x,x总是true(因为x为一个数值),那么or表达式的结果为x or y,结果为x。

当 x<y,第一个and表达式的结果为false,那么or表达式的值就为false or y,结果为y。


'not'操作符总是返回true或者false

[plain] view plain copy

  1. print(not nil) --> true
  2. print(not false) --> true
  3. print(not 0) --> false
  4. print(not not nil) --> false


4.连接操作符

Lua用'..'(两个点)来表示string连接符。如果它的任一个操作数为数字,Lua会把它转为string。

[plain] view plain copy

  1. print("Hello " .. "World") --> Hello World
  2. print(0 .. 1) --> 01

不要忘了,Lua中的string是常量。string连接操作符会创建一个新的string,不会对它的操作数有任何修改

[plain] view plain copy

  1. a = "Hello"
  2. print(a .. " World") --> Hello World
  3. print(a) --> Hello


5.优先级

Lua中的操作符优先级,如下表所示,从高到低

[plain] view plain copy

  1. ^
  2. not # -(单目)
  3. * / %
  4. + -
  5. ..
  6. < > <= >= ~= ==
  7. and
  8. or

除了'^和'..',所有的双目操作符都是左关联的。因此,下表中,左面的表达式和右面的表达式是等价的

[plain] view plain copy

  1. a+i < b/2+1 <--> (a+i) < ((b/2)+1)
  2. 5+x^2*8 <--> 5+((x^2)*8)
  3. a<y and y<=z <--> (a<y) and (y<=z)
  4. -x^2 <--> -(x^2)
  5. x^y^z <--> x^(y^z)

在有疑问的时候,就用括号'()',这比查手册更方便和简单,而且,当你以后看代码的时候,你可能仍然有同样的疑问,显式地使用括号'()'会更直观一点


6.表构造函数

构造函数是一个用来初始化表(table)的表达式。它是Lua的一个独特特性和很强大的功能之一。


最简单的构造函数是空构造函数,{},创建一个空table。构造函数也可以初始化数组,例如:

[plain] view plain copy

  1. days = {"Sunday", "Monday", "Tuesday", "Wednesday",
  2. "Thursday", "Friday", "Saturday"}

将day[1]初始化为"Sunday", day[2]为"Monday",注意,index是从1开始
[plain] view plain copy

  1. print(day[4]) --> Wednesday

Lua提供一个专门的语法去初始化record-like table,如下:

[plain] view plain copy

  1. a = {x=10, y=20}

等价于

[plain] view plain copy

  1. a = {}, a.x = 10; a.y = 20

不管我们用什么构造函数去创建一个table,我们都可以增加或减少结果中的field:

[plain] view plain copy

  1. w = {x=0, y=0, label="console"}
  2. x = {math.sin(0), math.sin(1), math.sin(2)}
  3. w[1] = "another filed" -- add key 1 to table 'w'
  4. x.f = w -- add key 'f' to table 'x'
  5. print(w["x"]) --> 0
  6. print(w[1]) --> another field
  7. print(x.f[1]) --> another field
  8. w.x = nil -- remove field 'x'

也就是说,table创建过程是相同的。构造函数只是将其初始化而已。


Lua每次使用构造函数,都会创建并初始化一个新的table。因此,我们可以用table来实现一个list:

[plain] view plain copy

  1. list = nil
  2. for line in io.lines() do
  3. list = {next=list, value=line}
  4. end

这些代码从stdin读入行,然后存入一个list中,顺序跟读入的顺序相反。list中的每个node有两个field:value,包含行的内容,next,指向下一个node。下面的代码遍历这个list,并且打印它的内容:

[plain] view plain copy

  1. local l = list
  2. while l do
  3. print(l.value)
  4. l = l.next
  5. end

以上两段代码的示例:


(由于我们在栈上实现了list,打印的时候会是逆序的)。尽管实现很方便,但是我们在Lua程序中很少使用如上实现的list;List可以作为array得到更好的实现,我们会在后面再讲这个问题。


我们可在一个构造函数中同时使用record-style和list_style的初始化方式:

[plain] view plain copy

  1. polyline = {color="blue", thickness=2, npoints=4,
  2. {x=0, y=0},
  3. {x=-10, y=0},
  4. {x=-10, y=1},
  5. {x=0, y=1}
  6. }

上面的例子也说明了如何使用嵌套的构造函数来表示更复杂的数据结构。每一个polyline[i]都是一个table,表示一条记录(record):

[plain] view plain copy

  1. print(polyline[2].x) --> -10 --此处要注意index 1是从哪里开始的,下面的示例may be helpful
  2. print(polyline[4].y) --> 1


这两种形式的构造函数( record-style和list_style )都有一些局限性。一些负数或者string不能作为标识符。


因此,Lua提供了一种更通用的格式。在这个格式中,我们显式的写出每一个[index]。

[plain] view plain copy

  1. opnames = {["+"] = "add", ["-"] = "sub",
  2. ["*"] = "mul", ["/"] = "div"}
  3. i = 20; s = "-"
  4. a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s}
  5. print(opnames[s]) --> sub
  6. print(a[22]) --> ---

这个规则有点麻烦,但是更方便灵活:record-style和list_style是这个通用格式的两个特例而已。

[plain] view plain copy

  1. {x=0, y=0} <==> {["x"]=0, ["y"]=0}
  2. {"r", "g", "b"} <==> {[1]="r", [2]="g", [3]="b"}

有时候,你想要你的array的index从0开始(Lua默认从1开始),用下面的方式就可以了:

[plain] view plain copy

  1. days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}

现在,第一个值"Sunday", index为0 。它不会影响其他的field;"Monday"的index为1,因为它是构造函数中的第一个list值;其他的跟随。尽管实现很便利,但是不推荐这样用。Lua的很多内置函数都假设array的index从1开始,如果一个array从0开始,可能会在处理上有问题。


在最后一个元素后面,可以加逗号','。这个末尾的逗号','是可选的,但都是合法的:

[plain] view plain copy

  1. a = {[1]="red", [2]="green", [3]="blue",}

通过这个便利性,程序在生成Lua table的时候不需要对最后一个元素做特殊处理。


最后,我们可以使用分号';'来代替逗号',',你可以在用';'来分割table中的不同属性的部分,例如:

[plain] view plain copy

  1. {x=10, y=45; "one", "two", "three"}

免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部