网上搜了一下,挺多打印table的方案,基本思路都是一层一层递归遍历table。(我就是参考这种思路做的^_^)

但大部分都不支持双向引用的打印。我所指的双向引用,就是a引用b, b又直接或间接引用a。例如下面的双向链表:

local node1 = {}
local node2 = {}
local node3 = {} node1.value =
node1.pre = nil
node1.next = node2 node2.value =
node2.pre = node1
node2.next = node3 node3.value =
node3.pre = node2
node3.next = nil

像这样一个双链表,网上的很多方法,处理这种情况时,递归无法结束因为,node1 表里有个 node2, 遍历node2时,又发现有个node1,如此反复

那要怎么处理呢?我的方案是:把每个table的父级table用一个链表保存起来,当判断到当前要处理的table存在于父级链表里,就停止处理。

完整代码如下:

 ------ 把table转成string
-- sign 打印在最前面的一个标记
-- tab 待处理table
-- showAddress 是否显示table的地址
function TabToStr(sign, tab, showAddress) -- 缓存table地址,防止递归死循环
local tabs = {};
local check = function(cur_tab, key, parentKey, level)
local tempP = tabs[(level-) .. parentKey]
while tempP do
if tempP.id == tostring(cur_tab) then
return false;
end
tempP = tempP.parent;
end tabs[level .. key] = {};
tabs[level .. key].id = tostring(cur_tab);
tabs[level .. key].parent = tabs[(level-) .. parentKey]; return true;
end -- 处理直接传入table的情况
if tab == nil then
tab = sign;
sign = "table:";
end local targetType = type(tab);
if targetType == "table" then
local isHead = false;
local function dump(t, tKey, space, level)
local temp = {};
if not isHead then
temp = {sign or "table:"};
isHead = true;
end if tKey ~= "_fields" then
table.insert(temp, string.format("%s{", string.rep(" ", level)));
end
for k, v in pairs(t) do
local key = tostring(k);
-- 协议返回内容
if key == "_fields" then
local fields = {};
for fk, fv in pairs(v) do
fields[fk.name] = fv;
end
table.insert(temp, dump(fields, key, space, level))
-- 如果是table模拟的类,忽略。 以下划线开头的字段, 忽略
elseif key == "class" or string.sub(key, , string.len("_")) == "_" then
-- 这里忽略 elseif type(v) == "table" then
if check(v, key, tKey, level) then
if showAddress then
table.insert(temp, string.format("%s%s: %s\n%s", string.rep(" ", level+), key, tostring(v), dump(v, key, space, level + )));
else
table.insert(temp, string.format("%s%s: \n%s", string.rep(" ", level+), key, dump(v, key, space, level + )));
end
else
table.insert(temp, string.format("%s%s: %s (loop)", string.rep(" ", level+), key, tostring(v)));
end
else
table.insert(temp, string.format("%s%s: %s", string.rep(" ", level+), key, tostring(v)));
end
end
if tKey ~= "_fields" then
table.insert(temp, string.format("%s}", string.rep(" ", level)));
end return table.concat(temp, string.format("%s\n", space));
end
return dump(tab, "", "", );
else
return tostring(tab);
end
end

核心方法说明

check 方法, 检测父级table链表中是否存在当前table

dump 方法, 递归遍历table

上面代码在实际项目中测试可用,一般情况可以直接使用。但有些是根据项目情况填充的内容。想要理解或改写的话,看下面的精简dump方法

local function dump(t, tKey, space, level)
local temp = {};
table.insert(temp, string.format("%s{", string.rep(" ", level)));
for k, v in pairs(t) do
local key = tostring(k);
if type(v) == "table" then
if check(v, key, tKey, level) then
table.insert(temp, string.format("%s%s: \n%s", string.rep(" ", level+), key, dump(v, key, space, level + )));
else
table.insert(temp, string.format("%s%s: %s (loop)", string.rep(" ", level+), key, tostring(v)));
end
else
table.insert(temp, string.format("%s%s: %s", string.rep(" ", level+), key, tostring(v)));
end
end
table.insert(temp, string.format("%s}", string.rep(" ", level)));
return table.concat(temp, string.format("%s\n", space));
end

测试:

tab = {, , , , {, , , }}
-- 这里的node1就是上面贴出的双向链表
print (TabToStr("node1", node1, true))
print (TabToStr("node1", node1))
print (TabToStr(tab))

结果:

Lua 打印 table (支持双向引用的table)的更多相关文章

  1. Lua table之弱引用

    Lua采用了基于垃圾收集的内存管理机制,因此对于程序员来说,在很多时候内存问题都将不再困扰他们.然而任何垃圾收集器都不是万能的,在有些特殊情况下,垃圾收集器是无法准确的判断是否应该将当前对象清理.这样 ...

  2. Lua打印Table的数据结构工具类

    --这是quick中的工具,作用就是打印Lua中强大的table的结构, 当table的嵌套层级比较多的时候,这个工具非常方便,开发中必备的工具. --具体使用方法:local debug = req ...

  3. Lua打印table树形结构

    --这是quick中的工具,作用就是打印Lua中强大的table的结构, 当table的嵌套层级比较多的时候,这个工具非常方便,开发中必备的工具.--具体使用方法:local debug = requ ...

  4. lua序列化(支持循环引用)

    lua序列化 支持key类型为string, number 支持value类型为string, number, table, boolean 支持循环引用 支持加密序列化 支持loadstring反序 ...

  5. lua 怎样输出树状结构的table?

    为了让游戏前端数据输出更加条理,做了一个简单树状结构来打印数据. ccmlog.lua local function __tostring(value, indent, vmap) local str ...

  6. lua 与C通过c api传递table (2)

    本文转自http://blog.csdn.net/a_asinceo/article/details/49907903(感谢...) 一.单个参数的传递 首先我们在Lua中注册一个C类PJYCallb ...

  7. 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(上)

    前言: 好久没写文章了,最近先是重构IT恋.又重写IT恋中. Sagit框架也不断的更新,调整,现在感觉已完美了了相当的多. 今天不写教程,先简单分享一下技术内容. 1:见Block必有:#defin ...

  8. 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(下)- block中任性用self

    前言: 在处理完框架内存泄漏的问题后,见上篇:讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(中)- IOS不为人知的Bug 发现业务代码有一个地方的内存没释放,原因很也简单: ...

  9. css Table布局:基于display:table的CSS布局

    两种类型的表格布局 你有两种方式使用表格布局 -HTML Table(<table>标签)和CSS Table(display:table 等相关属性). HTML Table是指使用原生 ...

随机推荐

  1. git上传超过100m大文件

    1.git出错如下错误时 执行如下可解决错误: git rm --cache '大文件路径' git commit --amend -CHEAD git push 2.当必须上传大文件时.需借助git ...

  2. HearthBuddy 日志模块

    // Triton.Common.LogUtilities.CustomLogger // Token: 0x04000BD8 RID: 3032 private Level level_0 = Le ...

  3. pm2 配置方式

    1.命令生产默认示例配置文件pm2 ecosystem或pm2 init,运行默认会生成ecosystem.config.js配置文件 module.exports = { apps: [ { nam ...

  4. Android ListView多布局

    使用listview多布局会出现一点问题: 由于多个item布局给单一的item布局是不一样的,使用起来,contentview的复用会出现问题. 避免出现问题的有这几个方法: 1.重写 getVie ...

  5. js复选框实现全选、全不选、反选

    复选框为checkbox对象 通过input就可以将一个简单的复选框呈现在页面上 <input type="checkbox" /> 要实现的大概就是这样一个页面 思路 ...

  6. RabbitMQ学习之:(二)介绍 (转贴+我的评论)

    转自:http://lostechies.com/derekgreer/2012/03/05/rabbitmq-for-windows-introduction/ RabbitMQ for Windo ...

  7. idea使用generatorconfig生成

    在maven工程中的resource中创建generatorConfigxml配置generatorConfigxml的配置pomxml生成对象的两种方式方式一使用idea的maven插件直接快速生成 ...

  8. 转:获取windows凭证管理器明文密码

    1.运行cmdkey /list查看windows保存凭证 方法1.mimikaz mimikatz vault::cred 2.利用powershell尝试获取 windows 普通凭据类型中的明文 ...

  9. uni-app 手指左右滑动实现翻页效果

    首先给页面添加 touch 事件 <view class="text-area" @touchstart="start" @touchend=" ...

  10. vue定义global.js,挂载在vue原型上面使用

    首先在src目录下创建global目录,在global目录下创建index.js. export default { install(Vue) { var that = this // 1. 添加全局 ...