与 Lua Five 的兼容性 |
|
本页面的主要目标与 [Compat5-1] 相同,但形式上是一系列提示,而非一组文件。
Hisham 制作了一个 [兼容性模块,为 Lua 5.1 提供 Lua 5.2 风格的 API]。
参考文献
(括号中注明了更改所针对的目标 Lua 版本)
require() 调用(Lua 5.0 和 5.1)重写 require 的调用,以保存其返回值(另见下面的“module()”)。例如:
require"lib"
变为
local lib = require"lib"
参考文献
module()(Lua 5.1)可以移除对 module() 的调用,并将代码适配为返回一个包含导出函数的表。有几种方法可以适配代码。最简单的是:
local function func1(...) ... end local function func2(...) ... end return { func1 = func1, func2 = func2, }
某些模块可能需要另一种方法,例如:
local _M = {} function _M.func1(...) ... end function _M.func2(...) ... end return _M
参考文献
从 Lua 5.0 到 Lua 5.2 关于环境的更改很棘手,应手动更正。
table.getn() 的调用(Lua 5.0)
table.getn 仅在 Lua 5.0 中定义,在后续版本中建议使用长度运算符代替它(参阅关于 [table.getn 弃用的说明])。
如果 table.getn 仅在测试文件中使用,可以这样定义:
if string.find(_VERSION, " 5.0") then table.getn = function (t) if t.n then return t.n else local n = 0 for i in pairs(t) do if type(i) == "number" then n = math.max(n, i) end end return n end end end
在这种情况下,应考虑分发适用于不同 Lua 版本的独立文件。
for 构造(Lua 5.0)旧的构造很容易转换为与 Lua 5.X 兼容的形式:
for i,v in t do ... end
应重写为:
for i,v in pairs(t) do ... end
参考文献
for 和 repeat 中的变量作用域(Lua 5.0)从 Lua 5.0 到 Lua 5.1,隐式 for 变量和 repeat 中的局部变量的作用域发生了变化。这需要手动检查。
参考文献
没有办法编写与所有 Lua 5.X 版本都兼容的嵌套长字符串。应手动调整代码以避免这些构造。
自 Lua 5.1 起,定义了 lua_pushinteger 函数。尽管它是一个函数,但以下宏可以使 Lua 5.1/5.2 代码向后兼容 Lua 5.0:
#if !defined(LUA_VERSION_NUM) #define lua_pushinteger(L, n) lua_pushnumber(L, (lua_Number)n) #endif
luaL_reg(Lua 5.0)自 Lua 5.1 起更名为 luaL_Reg。这可以通过条件编译来解决:
#if !defined LUA_VERSION_NUM /* Lua 5.0 */ #define luaL_Reg luaL_reg #endif
自 Lua 5.1 起,定义了 lua_setfield 函数。因此,可以定义以下宏来使 Lua 5.1/5.2 代码向后兼容 Lua 5.0:
#if !defined(LUA_VERSION_NUM) #define lua_setfield(L, i, k) (lua_pushstring(L, k), lua_settable(L, i)) #endif
已弃用的函数 lua_getref() 和 lua_unref() 可以很容易地转换为兼容的调用。例如:
/* This code is compatible with previous versions (4.0) */ lua_getref(L, ref); lua_unref(L, ref);
应重写为:
/* This is Lua 5.X code *; lua_rawgeti(L, LUA_REGISTRYINDEX, ref); luaL_unref(L, LUA_REGISTRYINDEX, ref);
Lua 5.2 模块可以通过一个函数轻松兼容之前的 Lua 5.X 版本:luaL_setfuncs。
#if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501
/*
** Adapted from Lua 5.2.0
*/
static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkstack(L, nup+1, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */
int i;
lua_pushstring(L, l->name);
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(L, -(nup+1));
lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
lua_settable(L, -(nup + 3));
}
lua_pop(L, nup); /* remove upvalues */
}
#endif
另外,对 luaL_openlib() 和 luaL_register() 的调用应根据其第二个参数进行更改。
类似 luaL_openlib(L, NULL, lreg, x); 的调用应重写为 luaL_setfuncs(L, lreg, x);。
类似 luaL_openlib(L, name, lreg, x); 的调用应小心重写,因为会搜索并可能创建具有给定名称的全局表。
类似 luaL_register(L, NULL, lreg); 的调用应重写为 luaL_setfuncs(L, lreg, 0);。
类似 luaL_register(L, name, lreg); 的调用应小心重写,因为会搜索并可能创建具有给定名称的全局表。可能的情况下,应重写为 luaL_setfuncs(L, lreg, 0);。