OpenResty完全开发指南:构建百万级别并发的Web应用
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.6 运算

Lua里的运算有算术运算、关系运算、逻辑运算、字符串运算等。

3.6.1 算术运算

Lua的算术运算包括基本的加减乘除,取模运算使用“%”,幂运算使用“^”:

print(1 + 1, ", ", 5-3)         -- 加减法运算,输出2,2
print(2 * 4, ", ", 1 / 3)         -- 乘除法运算,输出8,0.33333333333333
print(5 % 2, ", ", 3 ^ 3)         -- 取模和幂运算,输出1,27

算术运算时可以混用字符串类型,Lua会自动把字符串转换为数字,但如果含有非数字字符无法转换就会出错,所以最好不要混用。

Lua不提供其他语言里的递增和递减操作符(可能的原因是“--”已经被用作注释语法了),递增递减操作只能使用标准的赋值形式,例如:

count = 10                        -- 一个整数变量
count = count + 1                -- 加1后赋值,相当于++count

3.6.2 关系运算

Lua的关系运算符与其他语言基本相同,如“>”“>=”“<”“<=”“==”,但不等比较使用的是“~=”,需要特别注意:

print(3.14 > 2.718)              -- 大于关系
print(1/3 == 2/6)                -- 等于关系
print('10' ~= 10)                -- 不等关系,注意运算符是“~=”,不是“! =”

在执行大于或小于比较操作时Lua会检查变量的类型,如果类型不同就会出错,例如:

print(1 > "0")                    -- 报错,无法执行

但“==”和“~=”的行为则不同,如果类型不同会直接返回false。

实际开发中比较常见的情况是比较字符串形式的数字,为了避免发生意外,必须用函数tonumber()/tostring()显式转换数字或字符串后再做比较运算,例如:

print(1 > tonumber('0'))          -- 大于比较,使用tonumber()后正常
print('10' == 10)                 -- 比较的类型不同,结果为false
print(tonumber('10') == 10)       -- 等于关系,结果为true

3.6.3 逻辑运算

Lua的逻辑运算符有and、or和not三个,但运算规则有些特殊:

■ nil和false认为是假,其他都是真,包括数字0;

■ x and y,如果x是真,返回y,否则返回x;

■ x or y,与and操作正好相反,如果x是真,返回x,否则返回y;

■ not x,只返回true/false,对x取反。

对于C程序员来说第一条规则需要特别注意,因为在C语言里0是假,和false等价,但在Lua语言里0是真,nil和false等价,在书写条件判断代码时必须小心。

下面的代码示范了Lua里的逻辑运算:

print(0 and 'abc')                --0是真,所以返回字符串’abc'
print(x or 100)                   -- x是全局变量,值是nil,返回100
print(not x)                      -- x是全局变量,值是nil,返回true

利用Lua逻辑运算的特性可以实现非常灵活的赋值功能:

local x = count or 100           -- 为x赋初值,count不存在则默认值是100
local y = a and b or c           -- 相当于a? b:c,由a的真假决定赋值b或c

3.6.4 字符串运算

Lua对字符串连接操作提供了一个特别的运算符“..”:

print('hello'..' '..'world')    -- 连接多个字符串

连接运算还可以自动把数字转换为字符串,无须显式调用tostring()函数:

print("room number is " .. 313) -- 可以直接连接数字,无须转换

虽然Lua可以高效地处理字符串,但字符串连接操作应当尽量少用,因为每一次字符串连接就会创建一个新的字符串对象,如果多次操作超长字符串(例如几十MB的大块数据)就可能会导致LuaVM内存耗尽,发生错误。

计算字符串的长度可以用另一个特别的运算符“#”:

print(#'openresty')              -- 计算字符串长度,输出9

字符串的关系运算基于字符序(例如最常用的ASCII码表)逐个检查,但相等比较是直接计算内部保存的散列值,速度很快(见3.4节):

print("a" < "b")                 -- 结果为true,字符序检查
print("zero" > "0")              -- 结果为true,字符序检查
print("abc" == "abc")            -- 结果为true,比较的是内部散列值

3.6.5 注意事项

在运算时我们需要注意操作数是nil的情形,很多时候对nil运算都会导致错误,例如:

x = nil                           -- x的值是nil
print(1 + x)                      -- 出错,无法执行加法运算
print("msg is "..x)               -- 出错,无法执行连接运算

如果一个变量可能是nil,最好使用or运算给它一个默认值:

print(1 + (x or 2))              -- 正常,x不存在则使用2执行加法运算
print("msg is ".. (x or "-"))    -- 正常,x不存在则使用"-"执行连接运算