19.Lua版本差异
19.1 知识点
判断Lua运行时
不同项目嵌的 Lua 运行时不一样。大部分语法按 Lua 5.1 跑通是没问题的,但是还是要看看实际运行时版本。
常见:LuaJIT、Lua 5.1~5.4、项目魔改 Lua、xLua / toLua / SLua 内置运行时。
第一步确认当前脚本跑在哪个 Lua 运行时上。
print(_VERSION)
可能输出 Lua 5.1 或 Lua 5.3 等。LuaJIT 环境下 _VERSION 也可能显示 Lua 5.1,所以还要看 jit.version:
if jit then
print(jit.version)
end
同时还要看项目接入文档、Lua DLL/so 版本、框架说明、标准库和语法支持情况。以项目真正跑起来的那个运行时为准。
| 版本 | 常见差异点 | 项目里怎么记 |
|---|---|---|
| LuaJIT | Lua 5.1 语义为主,内置 bit,带部分 Lua 5.2 / 5.3 扩展 |
不能当成完整 Lua 5.3 / 5.4;部分扩展要看 LuaJIT 版本和编译开关 |
| Lua 5.1 | unpack、setfenv/getfenv、module |
老项目、Unity Lua 热更、LuaJIT 体系里常见 |
| Lua 5.2 | _ENV、goto、__pairs / __ipairs |
环境机制从 setfenv 转向 _ENV,迭代元方法注意版本差异 |
| Lua 5.3 | 整数 / 浮点、原生位运算、table.move、utf8 |
新运算和操作语法 |
| Lua 5.4 | incremental / generational GC、<close>、__close、coroutine.close |
资源关闭和协程关闭语义 |
LuaJIT
LuaJIT 是偏性能的 Lua 运行时,带 JIT 优化,接近 Lua 5.1。
内置 bit 库,位运算用 bit.band / bit.bor / bit.bxor。
LuaJIT 2.1 带部分 5.2 / 5.3 扩展;
兼容行为要看编译开关。比如__pairs / __ipairs 得看 LUAJIT_ENABLE_LUA52COMPAT。
Lua 5.1 :一套 Lua 语言版本和标准解释器。
LuaJIT :主要按 Lua 5.1 语义,内部做了 JIT 优化和扩展。
Lua 5.3/5.4 :Lua 官方后续版本,有新语法和新标准库。
Lua 5.1
unpack
local t = { 1, 2, 3 }
print(unpack(t)) -- 1 2 3
5.2+ 用 table.unpack(t)。5.1里 unpack(t) 把连续数组拆成多个返回值。
setfenv和getfenv
环境是函数查全局变量表。没写 local 的变量会去默认全局表找:
value = 100
function TestEnv()
print(value)
end
TestEnv() -- 100
setfenv 把查找环境换成指定表:
local env = {
print = print,
value = 123
}
function TestEnv()
print(value)
end
setfenv(TestEnv, env)
TestEnv() -- 123
换了环境后,print 也要放进 env,否则报错:
local env = {
value = 123
}
function TestEnv()
print(value)
end
setfenv(TestEnv, env)
-- TestEnv() -- 报错,因为 env 里没有 print
getfenv 取出函数当前环境表:
local env = {
print = print,
value = 123
}
function TestEnv()
print(value)
end
setfenv(TestEnv, env)
local currentEnv = getfenv(TestEnv)
print(currentEnv == env) -- true
print(currentEnv.value) -- 123
setfenv(函数, 表):换查找环境。getfenv(函数):拿当前环境表。
老 5.1 代码里还可能见到 module("M", package.seeall)是搞成一个表返回;新代码用 return 表导出模块。
5.2 改成用 _ENV,沙盒、限制全局访问会用到。
Lua 5.2
重点:_ENV、goto、__pairs / __ipairs;setfenv / getfenv 不再作常规写法。
_ENV
当前代码查非 local 变量用的那张表。
value = 100
function Test()
print(value)
end
Test() -- 100
local env = {
print = print,
value = 123
}
local function Test()
local _ENV = env
print(value)
end
Test() -- 123
_ENV 换成 env 后,print 也去 env 里找,所以 env 里要有 print:
local env = {
value = 123
}
local function Test()
local _ENV = env
print(value)
end
-- Test() -- 报错,因为 env 里没有 print
Lua 5.1:setfenv 改函数环境。
Lua 5.2:_ENV 换查找环境。
_ENV 决定当前代码查非 local 变量时用的那张表。
goto
标签 ::name::,跳转 goto name。
local i = 1
::begin::
print(i)
i = i + 1
if i <= 3 then
goto begin
end
输出 1、2、3,效果和 while i <= 3 差不多。业务里不要滥用 goto,逻辑跳跃不好排查。
Lua 5.3
整数和浮点
区分 integer / float:
print(type(1)) -- number
print(type(1.0)) -- number
print(math.type(1)) -- integer
print(math.type(1.0)) -- float
原生位运算
print(1 & 3) -- 按位与,输出 1
print(1 | 2) -- 按位或,输出 3
print(1 ~ 3) -- 按位异或,输出 2
print(1 << 2) -- 左移,输出 4
print(8 >> 1) -- 右移,输出 4
1 = 01,3 = 11
01
& 11
----
01 → 1
5.1 / LuaJIT 一般用 bit、bit32 或项目封装`。
table.move
table.move(源表, 起始索引, 结束索引, 目标起始索引, 目标表)
local source = { 1, 2, 3, 4, 5 }
local target = {}
table.move(source, 2, 4, 1, target)
print(target[1]) -- 2
print(target[2]) -- 3
print(target[3]) -- 4
把 source[2] 到 source[4] 搬到 target[1] 开始的位置。
source[2]=2 -> target[1]
source[3]=3 -> target[2]
source[4]=4 -> target[3]
原表值还在:
print(source[2]) -- 2,原来的 source 里还在
utf8库
# 是字节长度,不是中文字符数。5.3 的 utf8 库补 UTF-8 工具:
local str = "你好"
print(#str) -- 通常输出 6,因为 UTF-8 中文一般一个字 3 字节
print(utf8.len(str)) -- 输出 2,表示 2 个 UTF-8 字符
有些项目可能用自己封装的字符串工具。
Lua 5.4
分代GC
默认新对象大多活不久,所以它频繁只扫“新对象”做 minor GC,少量存活久的对象晋升为老对象,老对象不每次都扫,只在必要时做 major GC 全量回收。
19.2 知识点代码
Lesson19_Lua版本差异.lua
print("**********Lua版本差异************")
print("**********知识点一 判断Lua运行时************")
-- _VERSION 看基础版本;LuaJIT 下也可能打印 Lua 5.1
print("当前 _VERSION:", _VERSION) -- 输出:Lua 5.1(本机示例)
if jit then
print("当前运行环境:LuaJIT")
print("LuaJIT 版本:", jit.version)
else
print("当前运行环境:非 LuaJIT 或未暴露 jit 表")
end
-- 还要看接入文档、DLL 版本、框架说明、标准库和语法支持
print("**********知识点二 LuaJIT************")
-- 接近 5.1;位运算用 bit.band / bit.bor / bit.bxor,别默认能写 5.3 的 &、|、~
if jit then
local bit = require("bit")
-- bit.band:按位与,效果同 1 & 3
-- 01
-- & 11
-- ----
-- 01
local value = bit.band(1, 3)
print("bit.band(1, 3):", value) -- 输出:1
else
print("当前不是 LuaJIT,跳过 bit 库示例")
end
-- LuaJIT 2.1 可能带部分 5.2/5.3 扩展;__pairs/__ipairs 看编译开关
print("**********知识点三 Lua 5.1************")
print("----------unpack----------")
local unpackFunc = unpack or table.unpack
if unpackFunc then
local t = { 1, 2, 3 }
print(unpackFunc(t)) -- 输出:1 2 3,5.1 用 unpack;5.2+ 用 table.unpack
else
print("当前运行时没有 unpack / table.unpack")
end
print("----------setfenv和getfenv----------")
if setfenv and getfenv then
local env = {
print = print,
value = 123
}
function TestEnv()
print(value)
end
setfenv(TestEnv, env)
TestEnv() -- 输出:123
local currentEnv = getfenv(TestEnv)
print(currentEnv == env) -- 输出:true
print(currentEnv.value) -- 输出:123
else
print("当前运行时没有 setfenv / getfenv,5.2+ 用 _ENV")
end
-- 老 5.1 代码还可能见到 module("M", package.seeall),要认识;新代码用 return 表导出
print("**********知识点四 Lua 5.2************")
-- _ENV / goto 在 5.1 文件里不能直接跑,下面只做版本提示
--[[
local env = {
print = print,
value = 123
}
local function Test()
local _ENV = env
print(value) -- 输出:123
end
Test()
]]
--[[
local i = 1
::begin::
print(i) -- 依次输出:1 / 2 / 3
i = i + 1
if i <= 3 then
goto begin
end
]]
print("5.2:_ENV 换查找环境;goto 做跳转;__ipairs 到 5.3 已废弃")
print("**********知识点五 Lua 5.3************")
print("----------整数和浮点----------")
print(type(1)) -- 输出:number
print(type(1.0)) -- 输出:number
if math.type then
print(math.type(1)) -- 输出:integer
print(math.type(1.0)) -- 输出:float
else
print("当前运行时没有 math.type,跳过 integer / float 子类型")
end
print("----------原生位运算----------")
-- 5.3+ 才有 & | ~ << >>;5.1/LuaJIT 用 bit 库
--[[
print(1 & 3) -- 输出:1
print(1 | 2) -- 输出:3
print(1 ~ 3) -- 输出:2
print(1 << 2) -- 输出:4
print(8 >> 1) -- 输出:4
]]
print("----------table.move----------")
if table.move then
local source = { 1, 2, 3, 4, 5 }
local target = {}
table.move(source, 2, 4, 1, target)
print(target[1], target[2], target[3]) -- 输出:2 3 4
print(source[2]) -- 输出:2,原表还在
else
print("当前运行时没有 table.move")
end
print("----------utf8库----------")
if utf8 and utf8.len then
local str = "你好"
print(#str) -- 输出:6,字节长度
print(utf8.len(str)) -- 输出:2,UTF-8 字符数
else
print("当前运行时没有 utf8.len")
end
print("**********知识点六 Lua 5.4************")
-- 5.4 分代 GC:新对象多走 minor GC,存活久的晋升老对象,major GC 全量回收
print("5.4 分代 GC:新对象多做 minor,存活久的晋升老对象,按需 major 全量回收")
if collectgarbage then
print("collectgarbage 可用,当前内存约:", collectgarbage("count"), "KB")
else
print("当前运行时无 collectgarbage")
end
print("**********总结************")
print("1. 先 print(_VERSION);LuaJIT 还要看 jit.version。")
print("2. LuaJIT 接近 5.1,位运算用 bit,别当成完整 5.3/5.4。")
print("3. 5.1:unpack、setfenv/getfenv。")
print("4. 5.2:_ENV、goto、__pairs/__ipairs。")
print("5. 5.3:integer/float、位运算、table.move、utf8。")
print("6. 5.4:incremental / generational 分代 GC。")
print("7. 以项目真正跑起来的运行时为准。")
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com