设为首页 加入收藏

TOP

lua序列化(支持循环引用)(一)
2014-11-23 19:00:31 】 浏览:308
Tags:lua 序列化 支持 循环 引用
lua序列化
支持key类型为string, number
支持value类型为string, number, table
支持循环引用
支持 加密序列化
支持loadstring反序列化
使用示例
local t = { a = 1, b = 2}
local g = { c = 3, d = 4, t}
t.rt = g
local ser_str = ser(g)
local unser_table = loadstring(sered)()
原理详解
采用递归序列化表的方式实现,并且支持循环引用,实现思路参考了云风的序列化,从云风那里学到了不少东西。
先说不考虑支持循环引用的简单情况,采用递归方式实现序列化很简单
直接使用type函数分别判断表中key-value对儿分别是什么数据类型,然后分别处理
序列化key
local keystr = nil
if type(k) == "string" then
keystr = string.format("[\"%s\"]", k)
elseif type(k) == "number" then
keystr = string.format("[%d]", k)
end
序列化value
local valuestr = nil
if type(v) == "string" then
valuestr = string.format("\"%s\"", tostring(v))
elseif type(v) == "number" then
valuestr = tostring(v)
elseif type(v) == "table" then
valuestr = table_ser(v, fullkey, mark, assign)
end
分别处理完key和value直接插入一个表容器中就可以,最后在使用table.concat连接字符串就可以,这里要说一下lua中拼接字符串是个比较低效的行为,这跟lua字符串实现有关,每拼接都会重新生成一个新串,所以字符串越长拼接会越慢
这里使用table.concat,不但减少了拼接次数,而且这样拼接效率比较高,因为是调用C拼接,而非Lua字符串的行为
return string.format("{%s}", table.concat(container, ","))
精简后的代码
local function table_ser(tableva lue)
-- 记录表中各项
local container = {}
for k, v in pairs(tableva lue) do
-- 序列化key
local keystr = nil
if type(k) == "string" then
keystr = string.format("[\"%s\"]", k)
elseif type(k) == "number" then
keystr = string.format("[%d]", k)
end
-- 序列化value
local valuestr = nil
if type(v) == "string" then
valuestr = string.format("\"%s\"", tostring(v))
elseif type(v) == "number" then
valuestr = tostring(v)
elseif type(v) == "table" then
valuestr = table_ser(v, fullkey, mark, assign)
end
table.insert(container, string.format("%s=%s", keystr, valuestr))
end
return string.format("{%s}", table.concat(container, ","))
end
支持循环引用
其实普通序列化没什么好说的,重点在于对循环引用的支持思路参考了云风的实现
使用一个表mark记录所有序列化过的表,并记录其全key(从根表到当前表的全路径key)每次新序列化一个表时,首先查看是否已经序列化过,若没有序列化则直接序列化, 若已经序列化过则处理如下:
在一个表assgin中记录所有循环引用情况,并给出正确赋值(因为循环引用不能直接序列化,
所以间接的在表构造之后赋值),最后可以一起拼接到一起。
table序列化实现如下:
local function table_ser(tableva lue, tablekey, mark, assign)
-- 标记当前table, 并记录其key名
mark[tableva lue] = tablekey
-- 记录表中各项
local container = {}
for k, v in pairs(tableva lue) do
-- 序列化key
local keystr = nil
if type(k) == "string" then
keystr = string.format("[\"%s\"]", k)
elseif type(k) == "number" then
keystr = string.format("[%d]", k)
end
-- 序列化value
local valuestr = nil
if type(v) == "string" then
valuestr = string.format("\"%s\"", tostring(v))
elseif type(v) == "number" then
valuestr = tostring(v)
elseif type(v) == "table" then
-- 获得从根表到当前表项的完整key, tablekey(代表tableva lue的key), mark[v]代表table v的key
local fullkey = string.format("%s%s", tablekey, keystr)
if mark[v] then table.insert(assign, string.format("%s=%s", fullkey, mark[v]))
else valuestr = table_ser(v, fullkey, mark, assign)
end
end
if keystr and valuestr then
local keyvalues
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇二叉排序树 下一篇Java数据结构学习笔记之栈和队列..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目