运算符、表达式

 

表达式指由运算符连接变量、常量(例如数字、字符串)组成的语句,表达式计算、修改或返回一个值。

一、赋值

1、赋值

例如: a = 120;

如果将一个变量赋值为nil等同删除这个变量
table,userdata,functions.类型的数据在赋值时并不会创建新的值而只是添加一个引用(即始终指向同一个对象)。
将数据作为函数的参数时也会进行赋值操作,作为参数table,userdata,functions同样是按引用传递的。

2、多重赋值

a,b,c = 1,2,3;
以上的写法等效于 a=1;b=2;c=3;

多重赋值时,右边的操作数如果多于左边的变量数目则丢弃多余的,不足则返回nil。
a,b,c = 0; 结果是a等于 0 ,b,c都等于nil。而不是a,b,c都等于0。

如果一个函数有多个返回值时,也可以使用多重赋值的方法,例如:
x,y = mouse.getPos(); --取当前鼠标坐标,有两个返回值

二、算术运算符

加减乘除幂模:+ - * / ^ %
表示负值的操作符:-

%为求余,a % b 也可以写为 math.fmod(a,b) 或者 a - math.floor(a/b)*b;

三、关系运算符

大于: <
小于: >
小于等于:<=
大于等于:>=
等于: ==
不等于: ~=

关系运算符比较两个值并返回布尔值(truefalse),
数字类型则直接比较数值大小,字符串类型按字符的顺序比较字节码。
table,userdata,functions.类型的数据按引用比较而不是数据值,只有指向同一个对象时才返回true;

对不同数据类型进行比较时需要注意。
1、不同的数据类型默认是不相等的(除非对象重载了操作符) "10"==10 的结果是false
2、不能对不同的数据类型进行大小比较。

四、 逻辑运算符 and or not

逻辑与:and

and操作符要求两个操作数都为true,成功返回b,失败返回false.
例:a and b:如果a为false,则返回a(false或nil),否则返回b;
返回的是其中一个操作数并不是布尔值。

逻辑或:or

or操作符要求两个操作数其中之一为true,返回转换为布尔值等于true的操作数.
例:a or b:如果a为true,则返回a,否则返回b。
返回的是其中一个操作数并不是布尔值。


逻辑否:not

如要操作数为true则返回false,如果操作数为false则返回true.通俗一点说就是反过来取值的意思。

注意and、or运算符返回的是其中一个操作数并不是布尔值。
因为所有数据类型都可以转换为布尔值,所以这不妨碍逻辑运算。
在转换布尔值时LAScript认为false和nil是假(false),其他为真(true),0也被认为是true.

有时候我们在使用变量以前需要检测一个变量是否初始化。我们可能需要写下面的代码。
if( not img )then
    img = image.new();
end
我们可以利用or操作符更方便的实现上面的功能。
img = img or image.new();

五、连接运算符

..字符串连接,如果操作数不是字符串,LAScript将尝试自动转换为字符串,如果转换失败会报错。
str = "hello " .. "world" --> str为“hello world”

如果参与连接的操作数是一个数字,为避免与小数点混淆,需要在数字与连接运算符之间添加一个空格。

六、按位运算符

按位取反 ~

求反运算符~为单目运算符,具有右结合性。 其功能是对参与运算的数的各二进位按位求反。


按位与 &

按位与运算 按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。


按位或 |

按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。


按位异或 ~

按位异或运算符“~”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现

例:

print( (1 & 3) - ( 4 | 5 ) + ( 6 ~ 7 ) + ~8 ) ;


按位操作符是将数字以二进制形式按位比较,0作为假,1为真。

例如: c = 5 & 3;

我们先的看他们的二进制应当是怎么样的:

win.consoleOpen()

--数字转换为二进制字符串
str = string.format("%b",5 );
print(str); -->显示 101

--数字转换为二进制字符串
str = string.format("%b",3 );
print(str); -->显示 011

然后我们将 101 与 011 按位相与。
第一位不满足两个都是1的要求所以结果为0。
第二位也不满足两个都是1的要求所以结果为0。
每三位两个都是1,所以结果为1。
最后的结果就是 001,也就是1,所以c等于1;

win.consoleOpen()

--二进制字符串转换为数字
n = tonumber("001",2)
print(n); -->显示1

再看看实际的运算结果

win.consoleOpen()
print(5 & 3); -->显示1

七、计算对象长度

#运算符取得对象的长度,有点类似c++里的sizeof。
例如 #"abcd" == string.len("abcd");

八、运算符优先级

从高到底分别是:

^
not - (负值) #
* /
+ - ~ & |
..
< > <= >= ~= ==
and
or

除了^和..外所有的二元运算符都是左连接的.

使用括号可以改变优先级。如果记不住上面的优先级顺序,可以多用用括号。

九、运算符重载

对于一个table变量,我们可以重载运算符使之改变默认的运算方法。
每个table都可以指定一个元表(metatable),在元表中可以重载运算符。
重载的操作符实际上是一个函数,称之为表的元方法

table的元素可以是table自已。例: setmetatable(tab,tab);

下面是使用元表重载+操作符的示例:

tab =  {x=10,y=20};
tab2 = {x=12,y=22}
 
-- c = tab + tab2; --这样肯定会出错,因为 table默认是不能相加的
 
--创建一个元素,元表中的__add函数重载加运算符。
tmeta = {
    __add =  function(a,b) return a.x + b.x  end;
}
setmetatable(tab,tmeta);--为tab添加元表
 
c = tab + tab2; --这时候会调用重载的操作符
--上面的代码等效于
c = getmetatable(tab).__add(tab,tab2);

其他可以重载的操作符:


__index 索引操作符[]
如果读取表中不存在的键会触发__index元方法并返回值。
__index不但可以是一个函数,也可以是一个table对象(找不到成员就到__index指定的table里找)

b = a["不存在的键"] 调用 __index(a,"不存在的键")

函数原形: __index = function (t,k) end;

__newindex 索引操作符[]
当你给表的一个缺少的键赋值时会触发__newindex元方法。

a["不存在的键"] = "新的值" 调用 __newindex(a,"不存在的键","新的值")

函数原形: __newindex = function (t,k,v) end;

__gc 析构函数
__mode 弱引用
__eq 相等操作符==
a==b 调用 __eq(a,b)

a ~= b 转换为 not (a == b)

__add 加
a + b 调用 __add(a,b)

__sub 减
a - b 调用 __sub(a,b)

__mul 乘
a * b 调用 __mul(a,b)

__div 除
a / b 调用 __div(a,b)

__mod 模 %
a % b 调用 __mod(a,b)

__pow 冥 ^
a ^ b 调用 __pow(a,b)

__unm 负号 -
-a 调用 __unm(a)
__len 计算对象的长度 #
#a 调用 __len(a)

__lt 小于<
a < b 调用 __lt(a,b)

a > b 将被自动转换为 b < a

__le 小于等于<=
a <= b 调用 __le(a,b)

a >= b 转换为 b <= a.

__concat 连接操作符 ..
a..b 调用 __concat(a,b)

__call 调用操作符 ()
a() 调用 __call(a)

__not 按位取反操作符 ~
~a 调用 __not(a)

__and 按位与操作符 &
a & b 调用 __and(a,b)

__or 按位或操作符 |
a | b 调用 __or(a,b)

__xor 按位异或操作符 ~
a ~ b 调用 __xor(a,b)

一个常见的技巧,table是按引用比较的,即使他们的值相同,但只要不是指向同一个对象都被认为是不相等,
我们通过重载==运算符可以让两个tab按他们的存储值比较。

win.consoleOpen()
 
tab =  {x=10,y=20};
tab2 = {x=10,y=20}
 
print(tab==tab2);--默认是按引用比较,不指向同一个对象就不相等,结果为false
 
 
--创建一个元素,元表中的__eq函数重载比较运算符"=="。
tmeta = {
    __eq =  function(a,b) return ( (a.x == b.x) and (a.y == b.y) )  end;
}
setmetatable(tab,tmeta);--为tab添加元表
setmetatable(tab2,tmeta);--为tab2添加元表, 比较运算符需要为两个操作数添加同一个元表。
 
print( tab==tab2 ); --现在可以使用重载的==操作符按值比较了
--上面的代码等效于
print( getmetatable(tab).__eq(tab,tab2) );

userdata对象也是可以重载操作符的,但是没有必要的话建议您还是不要这样做。