Lua upgrade guide

Lua 升级手册,给只用过Lua 5.1 的用户(包括只用过 luajit 的用户)

3 minute read

Lua upgrade guide

Lua 升级手册,给只用过Lua 5.1 的用户(包括只用过 luajit 的用户)

介绍

Lua 5.1 版本是在2006年2月21号发布的,至到2011年12月下一个大版本5.2才正式发布,导致整个 Lua 社区对于5.1版本的依赖度非常高,又由于 luajit 一直只兼容 Lua 5.1 版本的 API,也导致一些想要兼容 luajit 的项目也不愿意提升自己依赖的 Lua 版本。

但是 Lua 5.3 版本在设计和语言的概念上是一个勇于对自己做减法的版本,在降低了语言复杂度的情况下,把一些问题设计的更好,并且去掉了被人诟病的 Lua 5.1 的 module 函数,所以我个人非常推荐大家直接使用 5.3 版本。(5.2 版本就现在来看只是一个中间版本)

由于网络上介绍 Lua 的资料,大多都会针对 5.1 版本,所以这篇文章的目的就是帮助大家了解一下基于 Lua 5.1,5.3 有些什么变化。

主要不兼容的特性列表

  1. table 可以设置 __gc 元表函数
  2. 添加了统一的环境表 _ENV 并取消了之前的函数环境表概念
  3. 移除了模块定义函数 module 推荐模块使用简单的 table 来实现
  4. 支持了 goto 指令
  5. 支持了数字整型类型,并且默认是64bit有符号整型
  6. 支持了 bit 操作符,可以对整型数字进行 bit 操作
  7. 基础的 utf8 支持
  8. string 库中支持了打包和解包的函数:string.pack, string.unpack

其中有一些修改特别需要注意,我会在下面详细介绍

ENV 环境表

在之前的版本中,会有一个 fenv 的概念,用来修改一个函数执行时的环境。环境简单的来说,就是全局变量所在的表,对于 Lua 来说,访问全局变量其实就是在访问一张特殊的表,这张表就叫做环境表。

在 Lua 5.1 世代,有一对函数用来获取和设置一个函数的环境表: setfenv getfenv 任何一段执行的代码都会包装成一个函数,并且会默认继承调用者的环境表。而最初的环境表就是默认的全局表: _G 。到了 5.2 世代之后,取消了这对函数,并且让所有运行的函数都会有一个 upvalue: _ENV ,这是一个特殊的变量,用来表示当前的环境表,你可以在任意的语句中操作或者修改这个环境表,当然你如果彻底替换了当前的 _ENV 表的话,所有的全局变量你都无法访问。

模块定义

5.1 世代推荐定义模块的做法是在模块定义的文件头部调用 module 方法,例如:

module("md5")
 
_M.calc = function (path) .... end

这样我们可以定义一个叫做 md5 的模块,并且在其他的地方使用。这样定义最大的缺点是,module 函数其实是将 md5 这个名称做为一个全局变量定义的,导致了全局表的污染。到了5.3世代之后,推荐的模块书写方法就完全改革,使用非常单纯的基础的 Lua 语法,就是在头部定义一个局部表,然后在这张表中填充方法,最后将这个表返回,例如:

local API = {}

function API.calc(path) ... end
 
function API.reset() ... end
 
return API

这样用户只要 require("md5") 之后就可以使用里面定义的函数,并且不会污染全局表。

字符串打包

在5.1世代,如果想要解析二进制协议中的数据是无法通过自带的函数库实现的,需要借助外部的字节操作库,或者是 structs 这个经典的 Lua 库来实现,不过到了 5.3 世代,通过字符串的打包 API 就可以实现所有的需求。

例如,解析 buffer 中头两个字节的大头序无符号长度: local len = string.unpack(buff, ">2H")

例如,将字符串写入buff中,并且先将字符串的长度以四个字节的 int 写入: local buff = string.pack("s4", str)

具体如何使用请参考 Lua 5.3 的官方手册

其他

其实,5.3 世代的 Lua 还有很多底层的修改,这些修改让 Lua 中的一些概念更加统一,例如之前不允许在 metamethods 中产生 yield 行为,在 ipairs 中不去使用你定义的 metamethod 中的遍历函数等等,这些修改是去掉了一些惊喜并且减少了一些对理解语言所需要掌握的概念,这些惊喜其实就是我们俗称的坑。

为了减少大家掉进坑里面的可能,我个人推荐在所有允许的地方都去使用 Lua 5.3 版本。

comments powered by Disqus