zoukankan      html  css  js  c++  java
  • Lua5.1 升级 Lua5.3 升级 小结

    Lua的版本差异确实是比较让人头疼的事情,之前在移动端一直采用Android下使用LuaJit,Ios下使用Lua5.1。这次升级到Xlua(lua5.3版本)主要有两方面的原因:一是ulua后续维护比价差,决定要升级到xlua,另一方面是公司在上线检查中提示禁止Luajit的使用(一些Crash无法解决),当然顺便解决了bit、64位问题。

    1. 改变

    参考:5.1 到 5.25.2 到 5.3云风:Lua 5.2 的细节改变

    2. Module

    5.2中抛弃module,建议使用require进行加载, 可能是考虑到Module定义对全局表的污染, 参考:抵制使用 module() 定义模块
    解决方案:

    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 底层实现从源代码层级对二者之间的区别进行了讨论。如果想要修改环境的同时还能访问全局变量

    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.2

    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位之后徐需要注意的是:

    • 原先的一些数学计算规则有些修改,至少碰到64位大数据除法溢出的问题,比如:local H3 = 0xffffffffffffff / 0x100000000,或者 math.random 如果传入浮点数会报错,需要调用math.floor 进行转化
    • 原先使用外部库进行64位数据处理可以转换到现有处理方式,b特别是以前5.1版本下protobuf的类库

    7. 小结

    从luajit升级到5.3版本问题都比较零碎,除了上面几个问题,还包括:

    • 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不同版本间兼容资源

  • 相关阅读:
    运维面试题之系统运维
    运维面试题之linux编程
    运维面试题之linux基础
    运维面试题之网络
    python 查找日志关键字
    python 数组中数字求和是否为零
    python 时间戳和时间格式互相转换
    Appium环境搭建说明(包括报错处理)
    python操作上级子文件
    去除ufeff的解决方法,python语言
  • 原文地址:https://www.cnblogs.com/zsb517/p/6822870.html
Copyright © 2011-2022 走看看