第 16 章 标准库精讲
第 16 章 标准库精讲
Lua 的标准库保持精简,核心能力集中在表、字符串、数学、操作系统、UTF-8 和调试模块。掌握这些接口的边界,可以减少不必要的第三方依赖。
math、os 与 table
math
print(math.abs(-8))
print(math.floor(3.9))
print(math.ceil(3.1))
print(math.max(1, 9, 4))
print(math.min(1, 9, 4))
print(math.sqrt(81))
print(math.tointeger(10.0)) -- 10
print(math.tointeger(10.5)) -- nil
math.type 区分整数和浮点数。浮点数比较应允许合理的误差:
local function nearlyEqual(left, right, epsilon)
return math.abs(left - right) <= (epsilon or 1e-9)
end
print(nearlyEqual(0.1 + 0.2, 0.3))
os
print(os.getenv("HOME"))
print(os.date("%Y-%m-%d %H:%M:%S"))
print(os.clock()) -- CPU 时间,不是墙上时钟
os.execute、os.remove、os.rename 和 os.tmpname 依赖宿主环境的权限与路径规则。嵌入式应用通常会禁用这些函数。
table
local values = { 3, 1, 2 }
table.sort(values)
print(table.concat(values, ","))
table.insert(values, 1, 0)
local removed = table.remove(values, #values)
print(removed)
table.move 可以复制区间:
local source = { "a", "b", "c" }
local target = {}
table.move(source, 1, #source, 1, target)
print(table.concat(target, ""))
排序比较函数必须满足严格弱序。比较函数抛错或不一致会导致 table.sort 结果未定义:
table.sort(values, function(left, right)
return left > right
end)
string 与 utf8
string 按字节工作,utf8 库处理 UTF-8 字符串:
local text = "Lua 教程"
print(#text)
print(utf8.len(text))
for position, codePoint in utf8.codes(text) do
print(position, codePoint, utf8.char(codePoint))
end
从位置 1 逐个取字符:
local position = 1
while position <= #text do
local codePoint = utf8.codepoint(text, position)
local nextPosition = utf8.offset(text, 2, position)
print(utf8.char(codePoint))
if not nextPosition then
break
end
position = nextPosition
end
utf8.offset 的边界语义容易出错。截取字符串前应先验证序列完整,不能随意按字节位置切割 UTF-8 文本。
模式匹配与二进制数据
Lua 字符串可以保存任意字节,包括 \0:
local binary = "A\0B"
print(#binary) -- 3
模式匹配处理二进制协议时,要明确哪些字节可打印,避免误把文本模式用于结构化数据。
日期与时间
os.time 返回时间戳,os.date 格式化时间:
local timestamp = os.time({
year = 2026,
month = 11,
day = 2,
hour = 10,
min = 30,
sec = 0
})
print(timestamp)
print(os.date("%Y-%m-%d %H:%M:%S", timestamp))
print(os.date("!%Y-%m-%dT%H:%M:%SZ", timestamp))
os.date 默认使用本地时区。格式前加 ! 使用 UTC。%c、%x 和 %X 与区域设置有关,机器可读日志应使用显式的 %Y-%m-%d 格式。
时间差
local function formatDuration(seconds)
local days = seconds // 86400
local remainder = seconds % 86400
local hours = remainder // 3600
remainder = remainder % 3600
local minutes = remainder // 60
local secs = remainder % 60
return string.format(
"%d 天 %02d:%02d:%02d",
days, hours, minutes, secs
)
end
os.clock 适合测量进程 CPU 时间,不适合作为业务事件时间。
随机数与安全随机性
需要可复现实验时使用固定种子:
math.randomseed(42)
print(math.random())
print(math.random(10))
print(math.random(5, 10))
生产环境需要不可预测令牌时,不要使用 math.random。Lua 标准库没有跨平台的密码学随机源,应通过宿主 C 扩展或操作系统的安全随机 API 获取。
即使使用 math.randomseed(os.time()),时间种子也可能被猜测。令牌、密码重置码和会话 ID 必须使用密码学安全随机数生成器。
洗牌
local function shuffle(values)
for index = #values, 2, -1 do
local target = math.random(index)
values[index], values[target] = values[target], values[index]
end
return values
end
随机数质量影响洗牌公平性。安全场景仍应使用宿主提供的安全随机实现。
标准库使用准则
-
用
math.type明确整数与浮点数语义。 -
用
utf8处理字符边界,不要用字节长度代替字符长度。 -
时间戳统一使用 UTC,展示层再转换时区。
-
不用
math.random生成安全令牌。 -
不向不可信脚本开放
io、os、package和debug。 -
对依赖宿主环境的函数封装一层,便于测试和替换。