运算符是编程语言的基础构建块,用于对操作数执行各种运算。Lua提供了丰富的运算符集合,理解这些运算符的内部实现和工作原理对于编写高效、正确的代码至关重要。
算术运算符用于执行数学运算。Lua 5.3+引入了整数和浮点数的明确区分,这对数值运算的精度和性能有重要影响。
| 运算符 | 说明 | 示例 | 结果 | 版本 |
|---|---|---|---|---|
| + | 加法 | 10 + 5 | 15 | 所有版本 |
| - | 减法 | 10 - 5 | 5 | 所有版本 |
| * | 乘法 | 10 * 5 | 50 | 所有版本 |
| / | 除法 | 10 / 4 | 2.5 | 所有版本 |
| // | 整除 | 10 // 4 | 2 | 5.3+ |
| % | 取模 | 10 % 3 | 1 | 所有版本 |
| ^ | 幂运算 | 2 ^ 3 | 8 | 所有版本 |
| - | 负号 | -10 | -10 | 所有版本 |
Lua 5.3+引入了整数和浮点数的明确区分:
-- 整数和浮点数的运算规则
print(10 + 5) -- 15 (整数)
print(10.0 + 5) -- 15.0 (浮点数)
-- 除法总是返回浮点数
print(10 / 2) -- 5.0
print(10 // 2) -- 5 (整除,返回整数)
-- 整数运算示例
local a = 2147483647 -- 最大32位有符号整数
local b = a + 1
print(b) -- 2147483648 (自动转换为浮点数)
-- 幂运算总是返回浮点数
print(2 ^ 10) -- 1024.0
print(4 ^ 0.5) -- 2.0 (平方根)
-- 取模运算的特殊性质
print(10 % 3) -- 1
print(-10 % 3) -- 2 (Lua的取模结果符号与除数相同)
print(10 % -3) -- -2
由于浮点数使用IEEE 754标准表示,存在精度限制:
-- 浮点数精度示例
print(0.1 + 0.2) -- 0.30000000000000004
print(0.1 + 0.2 == 0.3) -- false
-- 正确的浮点数比较方法
function almostEqual(a, b, epsilon)
epsilon = epsilon or 1e-10
return math.abs(a - b) < epsilon
end
print(almostEqual(0.1 + 0.2, 0.3)) -- true
-- 特殊浮点数值
print(1.0 / 0.0) -- inf (正无穷)
print(-1.0 / 0.0) -- -inf (负无穷)
print(0.0 / 0.0) -- nan (非数字)
print(math.sqrt(-1)) -- nan
关系运算符用于比较两个值,返回布尔结果。理解关系运算符的类型转换规则对于避免常见错误非常重要。
| 运算符 | 说明 | 示例 |
|---|---|---|
| == | 等于 | 5 == 5 (true) |
| ~= | 不等于 | 5 ~= 3 (true) |
| > | 大于 | 5 > 3 (true) |
| < | 小于 | 5 < 3 (false) |
| >= | 大于等于 | 5 >= 5 (true) |
| <= | 小于等于 | 5 <= 3 (false) |
b) -- false print(a < b) -- true print(a >= 10) -- true print(b <= 20) -- true -- 整数和浮点数混合比较 print(10 == 10.0) -- true print(10 < 10.5) -- true -- 字符串比较(字典序) print("abc" < "xyz") -- true print("ABC" < "abc") -- true (大写字母的ASCII码更小) print("10" < "2") -- true (按字典序,不是数值) -- 布尔值比较 print(false < true) -- true print(false == 0) -- false (不同类型) -- 表和函数的比较(引用比较) local t1 = {1, 2, 3} local t2 = {1, 2, 3} local t3 = t1 print(t1 == t2) -- false (不同的表对象) print(t1 == t3) -- true (同一个表对象) -- nil的比较 print(nil == nil) -- true print(nil < 1) -- 错误:不能比较nil和数字
逻辑运算符用于布尔逻辑运算,但Lua的逻辑运算符具有特殊的短路求值特性和灵活的返回值规则。
| 运算符 | 说明 | 示例 |
|---|---|---|
| and | 逻辑与 | true and false (false) |
| or | 逻辑或 | true or false (true) |
| not | 逻辑非 | not true (false) |
Lua中只有nil和false被视为假值,其他所有值(包括0、空字符串、空表)都是真值:
逻辑运算符具有短路特性,只在必要时才计算第二个操作数:
这种特性可以用于条件执行和默认值设置。
5 print(result1) -- nil (没有计算x > 5) -- or运算:第一个为真时短路 local result2 = 10 or x > 5 print(result2) -- 10 (没有计算x > 5) -- 短路求值的实际应用 -- 防止空指针错误 local t = nil local value = t and t.value -- 安全,不会报错 print(value) -- nil -- 默认值设置 local name = inputName or "匿名用户" -- 条件执行 x > 5 and print("x大于5") -- 相当于if x > 5 then print("x大于5") end -- 三元运算符的模拟 local max = (a > b) and a or b
逻辑运算符返回的是操作数的实际值,而不是简单的true/false:
位运算符用于对整数的二进制位进行操作。这些运算符在Lua 5.3中引入,主要用于底层编程和性能优化。
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
| & | 按位与 | 5 & 3 | 1 |
| | | 按位或 | 5 | 3 | 7 |
| ~ | 按位异或 | 5 ~ 3 | 6 |
| >> | 右移 | 8 >> 1 | 4 |
| << | 左移 | 4 << 1 | 8 |
| ~ | 按位非 | ~5 | -6 |
> 1) -- 4 (右移1位,相当于除以2) print(4 << 1) -- 8 (左移1位,相当于乘以2) print(1 << 3) -- 8 (左移3位) -- 按位非(取反) print(~5) -- -6 (二进制补码表示) -- 位运算的实际应用 -- 检查奇偶性 function isEven(n) return (n & 1) == 0 end print(isEven(4)) -- true print(isEven(5)) -- false -- 设置标志位 local flags = 0 flags = flags | (1 << 0) -- 设置第0位 flags = flags | (1 << 2) -- 设置第2位 print(flags) -- 5 -- 检查标志位 function hasFlag(flags, bit) return (flags & (1 << bit)) ~= 0 end print(hasFlag(flags, 0)) -- true print(hasFlag(flags, 1)) -- false
字符串连接使用..运算符。理解字符串连接的内存管理机制对于优化性能很重要。
在循环中连接字符串时,每次连接都会创建新的字符串对象,导致性能问题:
长度运算符#用于获取字符串或表的长度。
Lua中表的长度定义为"边界索引",即满足t[i]不为nil且t[i+1]为nil的最大整数i:
运算符优先级决定了表达式中运算的执行顺序。理解优先级规则对于编写正确的表达式至关重要。
从高到低的优先级:
^ (幂运算,右结合)not # - (一元运算符)* / // %+ -.. (字符串连接)< > <= >= ~= ==andor5 and 3 < 4) -- true print(10 > 5 or 3 < 4) -- true (短路)
通过元表机制,Lua支持运算符重载,使得自定义类型可以像内置类型一样使用运算符。
0 and b > 0 and c > 0 -- 逻辑运算 local isValid = isPositive and average > 10 -- 字符串连接 local result = string.format( "和: %d, 积: %d, 平均值: %.2f, 有效: %s", sum, product, average, tostring(isValid) ) return result end print(calculate(10, 20, 30)) -- 使用运算符重载的复数类 local Complex = {} Complex.__index = Complex function Complex.new(real, imag) local c = {real = real, imag = imag} setmetatable(c, Complex) return c end function Complex.__add(a, b) return Complex.new(a.real + b.real, a.imag + b.imag) end function Complex.__mul(a, b) return Complex.new( a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real ) end function Complex.__tostring(c) if c.imag >= 0 then return string.format("%g+%gi", c.real, c.imag) else return string.format("%g%gi", c.real, c.imag) end end local c1 = Complex.new(1, 2) local c2 = Complex.new(3, 4) print(c1 + c2) -- 4+6i print(c1 * c2) -- -5+10i
~= 而不是 !=// 和位运算符是Lua 5.3+新增的.. 而不是 +