第 4 章 运算符与表达式
第 4 章 运算符与表达式
Lua 的表达式由值、变量、函数调用和运算符组成。理解求值顺序与真值规则,是避免隐蔽 Bug 的基础。
算术与位运算符
算术运算
local a, b = 10, 3
print(a + b) -- 13
print(a - b) -- 7
print(a * b) -- 30
print(a / b) -- 3.3333333333333
print(a // b) -- 3
print(a % b) -- 1
print(a ^ b) -- 1000.0
/ 总是返回浮点数,// 执行向下取整除法。负数取模的结果符号与除数一致:
print(-7 // 3) -- -3
print(-7 % 3) -- 2
位运算
Lua 5.4 支持按位或 |、按位与 &、按位异或 ~、左移 <<、右移 >> 和一元按位非 ~:
print(5 | 2) -- 7
print(5 & 1) -- 1
print(5 ~ 1) -- 4
print(1 << 4) -- 16
print(~0) -- -1
位运算会把浮点数转换为整数。转换失败会报错,因此来自外部输入的数字应先校验。
比较与逻辑运算
比较
print(1 == 1.0) -- true
print("a" ~= "b") -- true
print(2 < 3) -- true
不同类型通常不能使用大小比较。需要比较字符串时,Lua 按字节序比较:
print("apple" < "banana") -- true
逻辑运算
and、or 和 not 都基于真值规则:
print(0 and "yes") -- yes
print(nil or "fallback") -- fallback
print(false or 0) -- 0
print(not nil) -- true
注意 and 和 or 返回参与运算的值,而不是固定返回布尔值。因此可以写默认值:
local function greet(name)
name = name or "访客"
return "你好," .. name
end
但默认值写法对 false 和 nil 都会触发回退。如果业务允许 false,应显式判断:
local function withDefault(value, default)
if value == nil then
return default
end
return value
end
字符串连接与长度
使用 .. 连接字符串或数字:
local name = "Lua"
local version = 5.4
print(name .. " " .. version) -- Lua 5.4
大量连接字符串时,反复创建中间字符串会带来开销。可以把片段放进表,最后使用 table.concat:
local parts = {}
for i = 1, 5 do
parts[#parts + 1] = "line-" .. i
end
print(table.concat(parts, "\n"))
# 返回字符串字节长度或表的边界长度。对含空洞的表使用 # 时结果不确定,应使用显式计数或遍历。
优先级与短路求值
Lua 常用优先级从高到低:
^
not # - ~
* / // %
+ -
..
<< >>
&
~
|
< > <= >= ~= ==
and
or
.. 是右结合的。and 和 or 具有短路行为:
local function expensive()
print("不会执行")
return true
end
local result = false and expensive()
print(result)
不要依赖复杂表达式的隐式优先级。对混合逻辑表达式使用括号,或用局部变量拆分步骤,可读性更高。
数字与字符串转换
算术运算会自动把数字字符串转换为数字:
print("10" + 2) -- 12
但显式转换更可靠:
local number = tonumber("10")
if number == nil then
error("不是有效数字")
end
local text = tostring(10)
print(number + 5, text .. " items")
tonumber 可以接收进制参数:
print(tonumber("ff", 16)) -- 255
print(tonumber("2.5")) -- 2.5
print(tonumber("abc")) -- nil
处理用户输入时始终检查 tonumber 是否返回 nil,不要依赖自动转换。