Lua5.1 升級 Lua5.3 升級 小結

Lua的版本差別確實是比較讓人頭疼的事情,以前在移動端一直採用Android下使用LuaJit,Ios下使用Lua5.1。此次升級到Xlua(lua5.3版本)主要有兩方面的緣由:一是ulua後續維護比價差,決定要升級到xlua,另外一方面是公司在上線檢查中提示禁止Luajit的使用(一些Crash沒法解決),固然順便解決了bit、64位問題。html

1. 改變

參考:5.1 到 5.25.2 到 5.3雲風:Lua 5.2 的細節改變git

2. Module

5.2中拋棄module,建議使用require進行加載, 多是考慮到Module定義對全局表的污染, 參考:抵制使用 module() 定義模塊
解決方案:github

  1. 經過luaconf.h.in中LUA_COMPAT_MODULE宏定義打開兼容支持
  2. 在Lua中自定義,以下:
local base = _ENV
local modname = {}
local _ENV = modname
...
return modname

3. setfenv/getfenv

在5.1版本,能夠理解爲每一個chunk都具備本身的環境表,而後經過setfenv/getfenv進行設置和操做。Lua5.2開始取消了環境表的概念,取消setfenv/getfenv方法,增長了_Env來管理。閉包

_ENV

  • *_Env*做爲chunk‘閉包的第一個upvalue,從 load 開始(初始化爲_G),第一個 chunk 就被加上了 _ENV 這個 upvalue ,而後依次傳遞下去。
  • 若是在某個chunk'中定義 *local _ENV={...}*其實就至關於修改這個chunk下面的環境。
  • Lua在編譯時會給變量名var變爲*_ENV.var*,
-- Lua 5.1 
    function foobar() 
    setfenv(1, {})
     -- code here 
    end 
    -- Lua 5.2 
    function foobar() 
    local _ENV = {} 
    -- code here 
    end

_G 和 _Env*

_G 是放在註冊表LUA_RIDX_GLOBALS中,初始化時核心的庫都放在_G中;_Env 是chunk閉包的第一個upvalue,load時默認爲_G, 而後後面定義的變量都會在編譯時加上_ENV.前綴,以此傳遞下去,固然也能夠修改。lua的註冊表,_ENV,_G 底層實現從源代碼層級對兩者之間的區別進行了討論。若是想要修改環境的同時還能訪問全局變量dom

a = 1  
local newgt = ()  
setmetatable(newgt, {__index = _G})  
_ENV = newgt  
print(a)    --> 1  
a = 10  
print(a)    --> 10  
print(_G.a) --> 1  
_G.a = 20  
print(_G.a) --> 20

Lua5.3 實現 SetFenv/GetFenv

5.2開始在Debug 類中提供了一些列關於upvalue操做的函數,經過這個方法能夠實現相似5.1中setfenv/getfenv的操做方式。詳細的過程能夠參考 這兩篇文章:
Implementing setfenv in Lua 5.2, 5.3, and above
Converting setfenv getfenv to Lua 5.2ide

local function getfenv(fn)
  local i = 1
  while true do
    local name, val = debug.getupvalue(fn, i)
    if name == "_ENV" then
      return val
    elseif not name then
      break
    end
    i = i + 1
  end
end

local function setfenv(fn, env)
  local i = 1
  while true do
    local name = debug.getupvalue(fn, i)
    if name == "_ENV" then
      debug.upvaluejoin(fn, i, (function()
        return env
      end), 1)
      break
    elseif not name then
      break
    end
    
    i = i + 1
  end
  return fn
end

4. 全局註冊表

在5.2中已經移除了LUA_GLOBALSINDEX,去而帶之的是註冊表。5.2之後中上面兩個函數都是使用的註冊標中的LUA_RIDX_GLOBAS僞索引(索引註冊表的全局環境)。處理 lua和C交互API的時候須要注意函數

5. luaL_register

Lua5.2 之後取消了這個接口,不過能夠經過luaL_setfunc方法看來實現大數據

#undef luaL_register
#define luaL_register(L,n,f) \
    { if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); }
#endif

6. 64位支持

Lua5.3 默認支持64位整數和浮點數,固然也能夠經過luaconf.h修改成32位。默認爲64位以後徐須要注意的是:ui

  • 原先的一些數學計算規則有些修改,至少碰到64位大數據除法溢出的問題,好比:local H3 = 0xffffffffffffff / 0x100000000,或者 math.random 若是傳入浮點數會報錯,須要調用math.floor 進行轉化
  • 原先使用外部庫進行64位數據處理能夠轉換到現有處理方式,b特別是之前5.1版本下protobuf的類庫

7. 小結

從luajit升級到5.3版本問題都比較零碎,除了上面幾個問題,還包括:lua

  • lua源代碼不平臺版本編譯(僅限不熟悉編譯的人)
  • lua-pb支持5.3 64位數據、替換struct、bit類庫等,固然你也能夠直接換個庫

github上也能夠找到一些實現好的類庫來知足不一樣版本之間的兼容,好比:Lua向下兼容github 庫Lua不一樣版本間兼容資源

參考

lua的註冊表,_ENV,_G 底層實現
抵制使用 module() 定義模塊
雲風 lua 5.2 的 _ENV
對lua中_ENV表的理解
Env環境
Implementing setfenv in Lua 5.2, 5.3, and above
Converting setfenv getfenv to Lua 5.2
Lua向下兼容github 庫
Lua不一樣版本間兼容資源

相關文章
相關標籤/搜索