與 Lua Five 的相容性

lua-users home
wiki

這個頁面提供一些開發人員可以採用的提示,以將寫給 Lua 5.1 的程式碼也轉換為與 Lua 5.0 和 Lua 5.2 相容。

此頁面的主要目標與 [Compat5-1] 相同,但形式是一系列提示,而非一組檔案。

Hisham 製作了一個 [相容性模組,為 Lua 5.1 提供 Lua-5.2 風格的 API]

參考資料

(括弧中說明變更所針對的 Lua 版本)

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.1)

與環境相關的 Lua 5.0 至 Lua 5.2 的變更很棘手,應手動修正。

移除對 table.getn() 的呼叫(Lua 5.0)

table.getn 僅在 Lua 5.0 中定義,較新的版本推薦使用 長度運算子 取代(請參閱 [關於移除 table.getn 的說明])。

如果僅在測試檔中使用 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

參考資料

forrepeat 中變數的範圍(Lua 5.0)

隱式 for 變數和 repeat 中的區域變數的範圍,在 Lua 5.0 到 Lua 5.1 期間有變更。這必須手動檢查。

參考資料

巢狀長字串(Lua 5.0)

沒有方法可以寫出與所有 Lua 5.X 版本相容的巢狀長字串。應手動調整程式碼以避免這種結構。

C 檔案

傳送整數(Lua 5.0)

從 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

定義 CFunctions 清單 (Lua 5.0)

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.0)

從 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 5.0 和 Lua 5.1)

不建議再使用的函數 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);

註冊 CFunctions (Lua 5.0 和 5.1)

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);


近期變更 · 偏好設定
編輯 · 歷史記錄
最後編輯於 2014 年 2 月 7 日星期五 下午 6:30 GMT (比較)