返回首页

教程导航

返回首页

🏷️ 标签(1)

🗂️ 分类(1)

第 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。

  • 对依赖宿主环境的函数封装一层,便于测试和替换。

上一章:文件与输入输出 | 下一章:C API 与嵌入式 Lua