虽然今天发了 twitter ,以及向 lua mailling list 里投递了消息,不过想想还是写一篇 blog 记录一下。
Lua 只支持一种 number ,默认是 double 类型。虽然你可以通过修改 luaconf.h 里的定义,把 lua number 改成 int64 。但是为了 int64 类型而放弃浮点数,恐怕不是大多数人想要的。
int64 通常用在 uuid 上,也就是说不需要对其数学运算,只需要可以比较就好了。我以前最喜欢的做法是用 8 bytes 长的 string 来表示一个 int64 。这样,即可以做唯一的 key 用,又不用做复杂的扩展。
在 pbc 的 lua binding 库 中,对 fixed64 类型,我就是这样处理的。
今天遇到新的需求,有同学希望可以在项目中直接处理 64bit 的 timestamp 。这就需要对 int64 做数学运算了。
虽然最终我们去掉了这个需求(使用 32bit 的 timestamp ),但我还是忍不住去想,到底怎样在 lua 中支持 64bit 整数运算最好。
在 luajit 中,是定义了一个 userdata 并重载其运算符完成的。即,你可以用 ffi.cast("int64_t",0)
来构造一个 64bit 的 0 。
姑且不谈 userdata 的额外开销问题,这样做有一个问题就是当 64bit 的 cdata 做 table 的 key 的时候,相同值的 int64 并不是同一个 key 。
我觉得有一个更轻量的方式来解决 int64 支持的问题。那就是在 64 位平台上,我们完全可以用 lightuserdata 无损失的表示一个 int64 。
通过给 lightuserdata 设置 metatable ,我们可以接管它的数据运算。唯一不足的是,比较一个 int64 和普通的 lua number 是否相等时,lua 不能隐式的做转换。(而大于小于比较则没有问题)
我花了半小时实现了我的想法,放在了 github 上 ,有兴趣的同学可以拿去用。
这个库只提供了一个显式的 api ,即构造一个 int64 数字。可以从 lua number 构造,也支持从一个 8 字节宽的小头的字符串来构造。实际在内存储存的是一个 lightuserdata 即一个 64bit 指针(所以这个库不适用于 32 位平台)。你也可以通过 C 接口 lua_pushlightuserdata
来把一个 64bit 整数压入堆栈。
把 int64 转换为普通的 lua number 借用了 # 操作符。
希望这个小东西对你有帮助。