%
操做符Lua 中的 %
操做符与 C 语言中的操做符虽然都是取模的含义,可是取模的方式不同。
在 C 语言中,取模操做是将两个操做数的绝对值取模后,在添加上第一个操做数的符号。
而在 Lua 中,仅仅是简单的对商相对负无穷向下取整后的余数。javascript
+++java
在 C 中,闭包
a1 = abs(a); b1 = abs(b); c = a1 % b1 = a1 - floor(a1/b1)*b1; a % b = (a >= 0) ? c : -c;
在 Lua 中,函数
a % b == a - math.floor(a/b)*b
Lua 是直接根据取模定义进行运算。 C 则对取模运算作了一点处理。code
+++对象
举例:blog
在 C 中ip
int a = 5 % 6; int b = 5 % -6; int c = -5 % 6; int d = -5 % -6; printf("a,b,c,d");--5,5,-5,-5
在 Lua 中内存
a = 5 % 6 b = 5 % -6 c = -5 % 6 d = -5 % -6 x = {a,b,c,d} for i,v in ipairs(x) do print(i,v) end --> 5 --> -1 --> 1 --> -5
能够看到,仅当操做数同号时,两种语言的取模结果相同。异号时,取模结果的符号与数值均不相等。字符串
在 Lua 中的取模运算总结为:a % b,若是 a,b 同号,结果取 a,b 绝对值的模;异号,结果取 b 绝对值与绝对值取模后的差。取模后值的符号与 b 相同。
比较操做的结果是 boolean
型的,非 true
即 false
。
支持的操做符有:
< <= ~= == > >=
不支持 !
操做符。
+++
对于 ==
操做,运算时先比较两个操做数的类型,若是不一致则结果为 false。此时数值与字符串之间并不会自动转换。
比较两个对象是否相等时,仅当指向同一内存区域时,断定为 true
。·
a = 123 b = 233 c = "123" d = "123" e = {1,2,3} f = e g = {1,2,3} print(a == b) --> false print(a == c) --> false -- 数字与字符串做为不一样类型进行比较 print(c == d) --> true print(e == f) --> true -- 引用指向相同的对象 print(e == g) --> false -- 虽然内容相同,可是是不一样的对象 print(false == nil) --> false -- false 是 boolean,nil 是 nil 型
方便标记,-->
表明前面表达式的结果。
+++
userdata
与 table
的比较方式能够经过元方法 eq
进行改变。
大小比较中,数字和字符串的比较与 C 语言一致。若是是其余类型的值,Lua会尝试调用元方法 lt
和 le
。
and,or,not
仅认为 false
与 nil
为假。
not
取反操做 not
的结果为 boolean
类型。(and
和 or
的结果则不必定为 boolean
)
b = not a -- a 为 nil,b 为 true c = not not a -- c 为 false
and
a and b
,若是 a
为假,返回 a
,若是 a
为真, 返回 b
。
注意,为何 a
为假的时候要返回 a
呢?有什么意义?这是由于 a
多是 false
或者 nil
,这两个值虽然都为假,可是是有区别的。
or
a or b
,若是 a
为假,返回 b
,若是 a
为真, 返回 a
。与 and
相反。
+++
提示: 当逻辑操做符用于得出一个 boolean
型结果时,不须要考虑逻辑运算后返回谁的问题,由于逻辑操做符的操做结果符合本来的逻辑含义。
举例
if (not (a > min and a < max)) then -- 若是 a 不在范围内,则报错 error() end
+++
and
与 or
遵循短路原则,第二个操做数仅在须要的时候会进行求值操做。
例子
a = 5 x = a or jjjj() -- 虽而后面的函数并无定义,可是因为不会执行,所以不会报错。 print(a) -->5 print(x) -->5
经过上面这个例子,咱们应当对于逻辑操做有所警觉,由于这可能会引入一些未能及时预料到的错误。
..
链接两个字符串(或者数字)成为新的字符串。对于其余类型,调用元方法 concat
。
#
对于字符串,长度为字符串的字符个数。
对于表,经过寻找知足t[n] 不是 nil 而 t[n+1] 为 nil 的下标 n 做为表的长度。
~~对于其余类型呢?~~
-- 字符串取长 print(#"abc\0") --> 4 -- 表取长 print(#{[1]=1,[2]=2,[3]=3,x=5,y=6}) --> 3 print(#{[1]=1,[2]=nil,[3]=3,x=5,y=6}) --> 1
由低到高:
or and < > <= >= ~= == .. + - * / % not # - (unary) ^
幂运算>单目运算>四则运算>链接符>比较操做符>and>or
Table 构造的 BNF 定义
tableconstructor ::= `{´ [fieldlist] `}´ fieldlist ::= field {fieldsep field} [fieldsep] field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp fieldsep ::= `,´ | `;´
BNF 定义参考 BNF范式简介 。
举例:
a = {} b = {["price"] = 5; cost = 4; 2+5} c = { [1] = 2+5, [2] = 2, 8, price = "abc", ["cost"] = 4} -- b 和 c 构造的表是等价的 print(b["price"]) --> 5 print(b.cost) --> 4 print(b[1]) --> 7 -- 未给出键值的,按序分配下标,下标从 1 开始 print(c["price"]) --> abc print(c.cost) --> 4 print(c[1]) --> 8 print(c[2]) --> 2
注意:
上面这两条的存在使得上面的例子中 c1 的输出值为 8。
+++
若是表中有相同的键,那么以靠后的那个值做为键对应的值。
a = {[1] = 5,[1] = 6} -- 那么 a[1] = 6
+++
若是表的最后一个域是表达式形式,而且是一个函数,那么这个函数的全部返回值都会加入到表中。
a = 1 function order() a = a + 1 return 1,2,3,4 end b = {order(); a; order(); } c = {order(); a; (order());} print(b[1]) --> 1 print(b[2]) --> 2 -- 表中的值并非一次把表达式都计算结束后再赋值的 print(b[3]) --> 1 print(b[4]) --> 2 -- 表达式形式的多返回值函数 print(#b) --> 6 -- 表的长度为 6 print(#c) --> 3 -- 函数添加括号后表的长度为 3
函数是一个表达式,其值为 function 类型的对象。函数每次执行都会被实例化。
Lua 中实现一个函数能够有如下三种形式。
f = function() [block] end local f; f = function() [block] end a.f = function() [block] end
Lua 提供语法糖分别处理这三种函数定义。
function f() [block] end local function f() [block] end function a.f() [block] end
+++
上面 local
函数的定义之因此不是 local f = function() [block] end
,是为了不以下错误:
local f = function() print("local fun") if i==0 then f() -- 编译错误:attempt to call global 'f' (a nil value) i = i + 1 end end
形参会经过实参来初始化为局部变量。
参数列表的尾部添加 ...
表示函数能接受不定长参数。若是尾部不添加,那么函数的参数列表长度是固定的。
f(a,b) g(a,b,...) h(a,...,b) -- 编译错误
f(1) --> a = 1, b = nil f(1,2) --> a = 1, b = 2 f(1,2,3) --> a = 1, b = 2 g(1,2) --> a = 1, b = 2, (nothing) g(1,2,3) --> a = 1, b = 2, (3) g(1,f(4,5),3) --> a = 1, b = 4, (3) g(1,f(4,5)) --> a = 1, b = 4, (5)
+++
还有一种形参为self的函数的定义方式:
a.f = function (self, params) [block] end
其语法糖形式为:
function a:f(params) [block] end
使用举例:
a = {name = "唐衣可俊"} function a:f() print(self.name) end a:f() --> 唐衣可俊 -- 若是这里使用 a.f(),那么 self.name 的地方会报错 attempt to index local 'self';此时应该写为 a.f(a)
:
的做用在于函数定义与调用的时候能够少写一个 self
参数。这种形式是对方法
的模拟
Lua 中的函数调用的BNF语法以下:
functioncall ::= prefixexp args
若是 prefixexp 的值的类型是 function, 那么这个函数就被用给出的参数调用。 不然 prefixexp 的元方法 "call" 就被调用, call 的第一个参数就是 prefixexp 的值,接下来的是 args 参数列表(参见 2.8 元表 | Metatable)。
函数调用根据是否传入 self
参数分为 .
调用和 :
调用。
函数调用根据传入参数的类型,能够分为参数列表调用、表调用、字符串调用。
[待完善]
若是一个函数访问了它的外部变量,那么它就是一个闭包。
因为函数内部的变量均为局部变量,外界没法对其进行访问。这时若是外界想要改变局部变量的值,那么就可使用闭包来实现这一目的。
具体的实现过程大体是这样,函数内部有可以改变局部变量的子函数,函数将这个子函数返回,那么外界就能够经过使用这个子函数来操做局部变量了。
例子:利用闭包来实现对局部变量进行改变
-- 实现一个迭代器 function begin(i) local cnt = i return function () -- 这是一个匿名函数,实现了自增的功能;同时它也是一个闭包,由于访问了外部变量 cnt cnt = cnt + 1 return cnt end end iterator = begin(2) -- 设置迭代器的初值为 2 ,返回一个迭代器函数 print(iterator()) -- 执行迭代 print(iterator())
提示: 关于闭包的更多说明可参考JavaScript 闭包是如何工做的?——StackOverflow
BNF范式简介 (简要介绍 BNF)
How do JavaScript closures work?——StackOverflow(详细介绍了 Javascript 中闭包的概念)