lua杂记

这里提供  Lua  中实现 OO 的一种方案:
local _class={}
 
function class(super)
	local class_type={}
	class_type.ctor=false
	class_type.super=super
	class_type.new=function(...) 
			local obj={}
			do
				local create
				create = function(c,...)
					if c.super then
						create(c.super,...)
					end
					if c.ctor then
						c.ctor(obj,...)
					end
				end
 
				create(class_type,...)
			end
			setmetatable(obj,{ __index=_class[class_type] })
			return obj
		end
	local vtbl={}
	_class[class_type]=vtbl
 
	setmetatable(class_type,{__newindex=
		function(t,k,v)
			vtbl[k]=v
		end
	})
 
	if super then
		setmetatable(vtbl,{__index=
			function(t,k)
				local ret=_class[super][k]
				vtbl[k]=ret
				return ret
			end
		})
	end
 
	return class_type
end


现在,我们来看看怎么使用:
base_type=class()		-- 定义一个基类 base_type
 
function base_type:ctor(x)	-- 定义 base_type 的构造函数
	print("base_type ctor")
	self.x=x
end
 
function base_type:print_x()	-- 定义一个成员函数 base_type:print_x
	print(self.x)
end
 
function base_type:hello()	-- 定义另一个成员函数 base_type:hello
	print("hello base_type")
end

以上是基本的 class 定义的语法,完全兼容 lua 的编程习惯。我增加了一个叫做 ctor 的词,作为构造函数的名字。
下面看看怎样继承:
test=class(base_type)	-- 定义一个类 test 继承于 base_type
 
function test:ctor()	-- 定义 test 的构造函数
	print("test ctor")
end
 
function test:hello()	-- 重载 base_type:hello 为 test:hello
	print("hello test")
end

现在可以试一下了:
a=test.new(1)	-- 输出两行,base_type ctor 和 test ctor 。这个对象被正确的构造了。
a:print_x()	-- 输出 1 ,这个是基类 base_type 中的成员函数。
a:hello()	-- 输出 hello test ,这个函数被重载了。 


lua md5库返回32个字符的: 

https://github.com/kikito/md5.lua 

序列化Lua表


这里是一个简单的 Lua table 序列化函数,只支持 number 或 string 做 key ,但是 value 可以是一个 table ,并支持循环引用:


function serialize(t)
	local mark={}
	local assign={}
	
	local function ser_table(tbl,parent)
		mark[tbl]=parent
		local tmp={}
		for k,v in pairs(tbl) do
			local key= type(k)=="number" and "["..k.."]" or k
			if type(v)=="table" then
				local dotkey= parent..(type(k)=="number" and key or "."..key)
				if mark[v] then
					table.insert(assign,dotkey.."="..mark[v])
				else
					table.insert(tmp, key.."="..ser_table(v,dotkey))
				end
			else
				table.insert(tmp, key.."="..v)
			end
		end
		return "{"..table.concat(tmp,",").."}"
	end
 
	return "do local ret="..ser_table(t,"ret")..table.concat(assign," ").." return ret end"
end
 
t = { a = 1, b = 2,}
g = { c = 3, d = 4,  t}
t.rt = g
 
print(serialize(t))


其输出将是这样的

do local ret={a=1,rt={c=3,d=4},b=2}ret.rt[1]=ret return ret end


为Lua扩展一个循环队列

这里展示用 lua 的 cclosure 扩展的一个技巧,实现了一个 lua 的循环队列:
参考:[InterWiki]lua cclosure 的 upvalue 数量限制

struct queue_data {
	int size;
	int head;
	int tail;
};
 
/* 
    当传入一个非 nil 的 lua 对象时,这个对象将进入队列。返回 true 表示成功,否则队列满
    当不传参数时,把队首元素出队列并返回出去;返回空表示队列空
 */
static int queue(lua_State *L)
{
	struct queue_data *qd=(struct queue_data*)g_api->lua_touserdata(L,lua_upvalueindex(1));
	if (g_api->lua_gettop(L)==0) {
		// queue leave
		if (qd->head==qd->tail) {
			return 0;
		}
		g_api->lua_pushvalue(L,lua_upvalueindex(qd->head));
		g_api->lua_pushnil(L);
		g_api->lua_replace(L,lua_upvalueindex(qd->head));
		++qd->head;
		if (qd->head > qd->size) {
			qd->head=2;
		}
		return 1;
	}
	else {
		// queue enter
		int tail=qd->tail+1;
		if (tail>qd->size) {
			tail=2;
		}
		if (tail==qd->head) {
			// queue overflow
			return 0;
		}
		g_api->lua_settop(L,1);
		g_api->lua_replace(L,lua_upvalueindex(qd->tail));
		qd->tail=tail;
		g_api->lua_pushboolean(L,true);
		return 1;
	}
}
 
/* 创建一个尺寸为 size 的队列对象并返回,size 收到 upvalue 数量限制,这里最大可以为 253 */
int queue_create(lua_State *L)
{
	struct queue_data *qd;
	g_api->lua_settop(L,1);
	int size=g_api->lua_tointeger(L,1)+2;
	if (size>253 || !g_api->lua_checkstack(L,size)) {
		return 0;
	}
	g_api->lua_settop(L,0);
	qd=(struct queue_data*)g_api->lua_newuserdata(L,sizeof(struct queue_data));
	qd->size=size;
	qd->head=qd->tail=2;
	g_api->lua_settop(L,size);
	g_api->lua_pushcclosure(L,queue,size);
	g_api->lua_pushvalue(L,-1);
	g_confirm_closure=g_api->lua_ref(L);
	return 1;
}

 树型打印一个 table


调试 lua 程序的时候往往想以树的形式打印出一个 table ,下面这个 print_r 函数可以满足要求。

local print = print
local tconcat = table.concat
local tinsert = table.insert
local srep = string.rep
local type = type
local pairs = pairs
local tostring = tostring
local next = next
 
function print_r(root)
	local cache = {  [root] = "." }
	local function _dump(t,space,name)
		local temp = {}
		for k,v in pairs(t) do
			local key = tostring(k)
			if cache[v] then
				tinsert(temp,"+" .. key .. " {" .. cache[v].."}")
			elseif type(v) == "table" then
				local new_key = name .. "." .. key
				cache[v] = new_key
				tinsert(temp,"+" .. key .. _dump(v,space .. (next(t,k) and "|" or " " ).. srep(" ",#key),new_key))
			else
				tinsert(temp,"+" .. key .. " [" .. tostring(v).."]")
			end
		end
		return tconcat(temp,"\n"..space)
	end
	print(_dump(root, "",""))
end


a = {}
 
a.a = { 
	hello = { 
		alpha = 1 ,
		beta = 2,
	},
	world =  {
		foo = "ooxx",
		bar = "haha",
		root = a,
	},
}
a.b = { 
	test = a.a 
}
a.c = a.a.hello
 
print_r(a)


输出:
+a+hello+alpha [1]
| |     +beta [2]
| +world+root {.}
|       +bar [haha]
|       +foo [ooxx]
+c {.a.hello}
+b+test {.a}


不用担心循环引用。



在 lua 中实现函数的重载

local function create()
	local arg_table = {}
	local function dispatcher (...)
		local tbl = arg_table
		local n = select ("#",...)
		local last_match
		for i = 1,n do
			local t = type(select(i,...))
			local n = tbl[t]
			last_match = tbl["..."] or last_match
			if not n then
				return last_match (...)
			end
			tbl = n
		end
		return (tbl["__end"] or tbl["..."])(...)
	end
	local function register(desc,func)
		local tbl = arg_table
		for _,v in ipairs(desc) do
			if v=="..." then
				assert(not tbl["..."])
				tbl["..."] = func
				return
			end
 
			local n = tbl[v]
			if not n then
				n = {}
				tbl[v]=n
			end
			tbl = n
		end
		tbl["__end"] = func
	end
	return dispatcher, register, arg_table
end
 
local all={}
 
local function register(env,desc,name)
	local func = desc[#desc]
	assert(type(func)=="function")
	desc[#desc] = nil
 
	local func_table
	if all[env] then
		func_table = all[env]
	else
		func_table = {}
		all[env] = func_table
	end
 
	if env[name] then
		assert(func_table[name])
	else
		env[name],func_table[name] = create()
	end
 
	func_table[name](desc,func)
end
 
define = setmetatable({},{
	__index = function (t,k)
		local function reg (desc)
			register(getfenv(2),desc,k)
		end
		t[k] = reg
		return reg
	end
})


下面试一下:

define.test {
	"number",
	function(n)
		print("number",n)
	end
}
 
define.test {
	"string",
	"number",
	function(s,n)
		print("string number",s,n)
	end
}
 
define.test {
	"number",
	"...",
	function(n,...)
		print("number ...",n,...)
	end
}
 
define.test {
	"...",
	function(...)
		print("default",...)
	end
}
 
test(1)
test("hello",2)
test("hello","world")
test(1,"hello")


输出:

number  1
string number   hello   2
default hello   world
number ...      1       hello


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值