应用
使用上的Tips:
Lua中除了nil和bool型的false,其余值的逻辑判断都为true,包括0。
Lua中异或和取反运算符都是“~”
用local保存频繁使用的全局func会省去查找过程,提升效率。
一个字符串有大量拼接操作时,一起拼接比一次次拼接高效;用table.insert,最后table.concat会比直接使用“…”拼接高效。
尾部扩充table时,t[#t+1] = v要比table.insert(t,v)快一点。
面向对象技巧:
metatables和metamethods是Lua实现多态的主要手段。
运算符重载,只读等均可以通过metamethods实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 vmcase(OP_ADD) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(ra, intop(+, ib, ic)); } else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { setfltvalue(ra, luai_numadd(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } vmbreak; } 以加法指令为例,非值类型的‘+’会检查元表中是否定义了TM_ADD("__add" )的元方法,如果有则使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function readOnly (t) local proxy = {} local mt = { __index = t, __newindex = function (t,k,v) error ("attempt to update a read-only table" , 2 ) end } setmetatable (proxy, mt) return proxy end 只读的实现如上,proxy是一张空表,访问任意key会转为访问__index ,即正常读取了t中的value; 而想要set时,则会触发__newindex 报错。 需要注意的是proxy可以正常的for ...pairs /ipairs 遍历,但#proxy等于0 。 因为前者会查找__index ,而后者不会,如有需要可以定义__len 。 __len = function (a) return #getmetatable (a).__index ; end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function TestObject ( n, t) local self = { -- private members name = n, tag = t, } -- private function self .Trace = function ( ) print ("name:" ..self .name..",tag:" ..self .tag); end -- public function local Run = function ( ) self .Trace(); print ("run" ); end return { Run = Run } end
References:
Lua Style Guide
Lua Performance Tips
Programming in Lua
原理
Lua Value
1 2 3 4 5 6 7 8 typedef union Value { GCObject *gc; /* collectable objects */ void *p; /* light userdata */ int b; /* booleans */ lua_CFunction f; /* light C functions */ lua_Integer i; /* integer numbers */ lua_Number n; /* float numbers */ } Value;
在5.3.4中,Value如上所示,多了lua_Integer,是一个宏定义,可以使用long long,即支持64位整形。同时在TValue中的type上也区分出了整数与浮点数。
Lua指令
编译或反编译查看opcode的工具:
基于寄存器的虚拟机
相比于基于堆栈的虚拟机
指令更复杂,需要指定寄存器。↓
相同逻辑,指令数更少,不需要大量push,pop操作。↓
速度更快,同时实现更为复杂。
其他
java虚拟机Dalvik也是基于寄存器的虚拟机。↓
不同语境下,一个脚本语言的名字可能承载了很多不同概念,比如提到Lua,可能是指Lua语言,Lua解释器或Lua虚拟机。它们是一个整体,但不是不可替换的,就像java同时有jvm和Dalvik两种广泛应用的虚拟机。
References:
The Implementation of Lua5.0
A No-Frills Intro To Lua5.1 VM Instructions