网上搜了一下,挺多打印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. Java终止线程的三种方式

    停止一个线程通常意味着在线程处理任务完成之前停掉正在做的操作,也就是放弃当前的操作. 在 Java 中有以下 3 种方法可以终止正在运行的线程: 使用退出标志,使线程正常退出,也就是当 run() 方 ...

  2. IntelliJ IDEA-配置文件位置

    关于配置文件的位置 一旦开始使用IDEA之后,就需要做很多的配置相关工作,使得IDEA越来越符合你的个人习惯,让你使用起来得心应手.而这些配置信息,都保存在C盘,比如我的就会默认保存在如图所示的位置 ...

  3. Eratos筛法(筛选素数)

    对于n以内的非素数必有k*n1=n(n1<n)  所以 可有p1,2p2,3p3把非素数筛选掉 实现代码: #include<iostream> #include<string ...

  4. fastadmin编辑内容,有下拉选择关联的内容,自定义的参数去获取相应的下拉内容

    1.可以到你的编辑页面中添加自定义条件 data-params='{"custom[shop_id]":"2"}'

  5. smaller programs should improve performance RISC(精简指令集计算机)和CISC(复杂指令集计算机)是当前CPU的两种架构 区别示例

    COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION In this section, we l ...

  6. MySQL:行锁、表锁、乐观锁、悲观锁、读锁、写锁

    1.锁的分类 1.1从对数据操作的类型来分 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响. 结论1: --如果某一个会话 对A表加了read锁,则 该会话 可以对A表进行读操作 ...

  7. leetcode 146. LRU Cache 、460. LFU Cache

    LRU算法是首先淘汰最长时间未被使用的页面,而LFU是先淘汰一定时间内被访问次数最少的页面,如果存在使用频度相同的多个项目,则移除最近最少使用(Least Recently Used)的项目. LFU ...

  8. C++中.cpp和.hpp的区别

    原文地址:https://blog.csdn.net/qzx9059/article/details/89210571 c++中 cpp和hpp我们可以将所有东西都放在一个.cpp文件内,编译器会将这 ...

  9. apache整合tomcat中的一些注意事项

    1.整合完毕后,需要把项目同时部署在apache和tomcat中,不然会报错找不到资源 2.可以把tomcat和apcahe的项目路径设置为同一个 3.使用java框架时容易出现异常:The requ ...

  10. 链接Linux工具(SecureCRT)

    SecureCRT下载 点我下载 http://download.csdn.net/download/weixin_39549656/10207279 安装 先运行注册机 链接 输入密码 出现以下界面 ...