本节将深入解析Lua所有标准库的API设计、实现原理、使用场景以及在Android平台的特殊适配和优化技巧。
-- 类型检查与转换
assert(type("") == "string") -- 类型判断
local n = tonumber("42") -- 安全转换
local s = tostring({}) -- 输出table地址
-- 环境控制
local env = {print=print}
setmetatable(env, {__index=_G})
setfenv(1, env) -- 修改当前环境
-- 元编程
local t = {}
debug.setmetatable(t, {__call=function() print("called!") end})
t() -- 输出"called!"
关键机制:
_G
是全局环境表,5.2+版本改用_ENV
词法变量setfenv
在5.2+已被移除,需通过_ENV
实现-- 模块加载优化
package.preload.mymod = function()
return {version="1.0"} -- 预加载模块
end
-- 搜索路径配置
package.path = package.path..";/data/data/com.example/files/?.lua"
-- 自定义加载器
table.insert(package.searchers, function(modname)
local asset = "lua/"..modname:gsub("%.", "/")..".lua"
if android.assetExists(asset) then
return load(android.readAsset(asset), modname)
end
end)
Android适配:
package.preload
package.cpath
加载-- Unicode安全处理
local function utf8len(s)
return select(2, s:gsub("[^\128-\193]", ""))
end
-- 模式匹配优化
local log = "ERR|2023-01-01|Invalid param|user=123"
local typ, date, msg = log:match("^(%a+)|([^|]+)|(.+)")
-- 高效字符串构建
local buf = {}
for i = 1, 100 do
buf[i] = "line"..i
end
local str = table.concat(buf, "\n")
性能陷阱:
..
拼接字符串-- 使用string.pack/unpack(5.3+)
local bin = string.pack(">i4 i2", 123456, 789)
local num, short = string.unpack(">i4 i2", bin)
-- 与Java交互
local ByteBuffer = luajava.bindClass("java.nio.ByteBuffer")
local bb = ByteBuffer.wrap(luajava.byteArray(bin))
bb:order(ByteBuffer.BIG_ENDIAN)
local intVal = bb:getInt()
跨平台注意:
-- 表克隆实现
local function clone(t, deep)
local copy = {}
for k, v in pairs(t) do
if deep and type(v) == "table" then
copy[k] = clone(v, true)
else
copy[k] = v
end
end
return copy
end
-- 数组去重
local function uniq(arr)
local seen, res = {}, {}
for _, v in ipairs(arr) do
if not seen[v] then
table.insert(res, v)
seen[v] = true
end
end
return res
end
优化技巧:
table.create(n)
in LuaJIT)-- 只读表实现
local function readonly(t)
return setmetatable({}, {
__index = t,
__newindex = function() error("readonly table") end,
__metatable = false
})
end
-- 默认值表
local defaults = {color="red", size=10}
local mt = {
__index = function(t, k)
return defaults[k]
end
}
local config = setmetatable({color="blue"}, mt)
设计模式:
__index
可设为函数或表,前者更灵活后者性能更好-- 安全文件读写
local function safeWrite(path, data)
local tmp = path..".tmp"
local f = assert(io.open(tmp, "wb"))
f:write(data)
f:close()
os.rename(tmp, path) -- 原子操作
end
-- 遍历目录(Android需通过JNI)
local function scanDir(path)
local p = io.popen("ls "..path)
for name in p:lines() do
print(name)
end
p:close()
end
Android限制:
/data/data/pkg
)无需权限即可访问-- 缓冲读取器
function lines(filename)
local f = assert(io.open(filename))
return function()
local line = f:read()
if not line then f:close() end
return line
end
end
-- 与Java流互操作
local is = activity.getAssets().open("data.txt")
local reader = luajava.newInstance("java.io.BufferedReader",
luajava.newInstance("java.io.InputStreamReader", is))
local line = reader:readLine() -- Java流读取
混合编程:
-- 平台识别
local isAndroid = package.config:sub(1,1) == "/"
and os.getenv("ANDROID_ROOT")
-- 执行命令(Android有限制)
local function exec(cmd)
local p = io.popen(cmd)
local output = p:read("*a")
p:close()
return output
end
-- 环境变量处理
local function getEnvBool(name)
local val = os.getenv(name)
return val and val:lower() == "true"
end
安全警告:
os.execute
可用性-- 高精度计时
local start = os.clock()
-- do something
print(string.format("耗时: %.2fms", (os.clock()-start)*1000))
-- 日期转换
local t = os.date("*t")
local timestamp = os.time({
year=2023, month=1, day=1,
hour=0, min=0, sec=0})
-- Android系统时间
local System = luajava.bindClass("java.lang.System")
local uptime = System:nanoTime() / 1e9
时间规范:
os.time
使用本地时区-- 随机数生成
math.randomseed(os.time())
local dice = math.random(1, 6)
-- 位运算(5.3+)
local flags = 0x01 | 0x04 -- 位或
local mask = flags & 0x05 -- 位与
-- 大整数处理
local MAX_INT32 = 2^31-1
local function safeAdd(a, b)
if a > MAX_INT32 - b then error("overflow") end
return a + b
end
数值安全:
-- 坐标转换
local function rotate(x, y, angle)
local rad = math.rad(angle)
local cos, sin = math.cos(rad), math.sin(rad)
return x*cos - y*sin, x*sin + y*cos
end
-- 屏幕适配
local density = activity.getResources().getDisplayMetrics().density
local function dp2px(dp)
return math.floor(dp * density + 0.5)
end
图形计算:
-- 获取调用栈
local function callTrace()
local trace = {}
for i = 2, 10 do
local info = debug.getinfo(i, "nSl")
if not info then break end
trace[#trace+1] = string.format("%s:%d in %s",
info.short_src, info.currentline, info.name or "?")
end
return table.concat(trace, "\n")
end
-- 钩子函数
debug.sethook(function(event, line)
print(event, line)
end, "l")
调试建议:
debug.getinfo
对性能有显著影响-- 简单性能分析
local function profile(fn)
local start = os.clock()
local count = debug.getinfo(fn, "u").nups
fn()
return os.clock() - start, count
end
-- 内存分析
local function memUsage()
collectgarbage()
return collectgarbage("count")
end
分析工具:
-- 调用Android API
local Activity = luajava.bindClass("android.app.Activity")
local Context = luajava.bindClass("android.content.Context")
-- 资源访问
local resID = activity.getResources()
.getIdentifier("icon", "drawable", activity.getPackageName())
-- 线程切换
activity.runOnUiThread(luajava.createProxy("java.lang.Runnable", {
run = function()
toast("Hello from UI thread")
end
}))
交互规范:
-- JNI优化
local jni = luajava.bindClass("com.example.JNIBridge")
local buffer = jni:getDirectBuffer() -- 避免数据拷贝
-- 对象池模式
local recycler = {
pool = {},
get = function(self, cls)
if #self.pool > 0 then
return table.remove(self.pool)
end
return luajava.new(cls)
end,
recycle = function(self, obj)
table.insert(self.pool, obj)
end
}
优化原则: