zoukankan      html  css  js  c++  java
  • Lua 打印 table (支持双向引用的table)

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

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

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

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

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

    完整代码如下:

     1 ------ 把table转成string
     2 -- sign 打印在最前面的一个标记
     3 -- tab 待处理table
     4 -- showAddress 是否显示table的地址
     5 function TabToStr(sign, tab, showAddress)
     6 
     7     -- 缓存table地址,防止递归死循环
     8     local tabs = {};
     9     local check = function(cur_tab, key, parentKey, level)
    10         local tempP = tabs[(level-1) .. parentKey]
    11         while tempP do
    12             if tempP.id == tostring(cur_tab) then
    13                 return false;
    14             end
    15             tempP = tempP.parent;
    16         end
    17 
    18         tabs[level .. key] = {};
    19         tabs[level .. key].id = tostring(cur_tab);
    20         tabs[level .. key].parent = tabs[(level-1) .. parentKey];
    21 
    22         return true;
    23     end
    24 
    25     -- 处理直接传入table的情况
    26     if tab == nil then
    27         tab = sign;
    28         sign = "table:";
    29     end
    30 
    31     local targetType = type(tab);
    32     if targetType == "table" then
    33         local isHead = false;
    34         local function dump(t, tKey, space, level)
    35             local temp = {};
    36             if not isHead then
    37                 temp = {sign or "table:"};
    38                 isHead = true;
    39             end
    40 
    41             if tKey ~= "_fields" then
    42                 table.insert(temp, string.format("%s{", string.rep("    ", level)));
    43             end
    44             for k, v in pairs(t) do
    45                 local key = tostring(k);
    46                 -- 协议返回内容
    47                 if key == "_fields" then
    48                     local fields = {};
    49                     for fk, fv in pairs(v) do
    50                         fields[fk.name] = fv;
    51                     end
    52                     table.insert(temp, dump(fields, key, space, level))
    53                     -- 如果是table模拟的类,忽略。 以下划线开头的字段, 忽略
    54                 elseif key == "class" or string.sub(key, 1, string.len("_")) == "_" then
    55                     -- 这里忽略
    56 
    57                 elseif type(v) == "table" then
    58                     if check(v, key, tKey, level) then
    59                         if showAddress then
    60                             table.insert(temp, string.format("%s%s: %s
    %s", string.rep("    ", level+1), key, tostring(v), dump(v, key, space, level + 1)));
    61                         else
    62                             table.insert(temp, string.format("%s%s: 
    %s", string.rep("    ", level+1), key, dump(v, key, space, level + 1)));
    63                         end
    64                     else
    65                         table.insert(temp, string.format("%s%s: %s (loop)", string.rep("    ", level+1), key, tostring(v)));
    66                     end
    67                 else
    68                     table.insert(temp, string.format("%s%s: %s", string.rep("    ", level+1), key, tostring(v)));
    69                 end
    70             end
    71             if tKey ~= "_fields" then
    72                 table.insert(temp, string.format("%s}", string.rep("    ", level)));
    73             end
    74 
    75             return table.concat(temp, string.format("%s
    ", space));
    76         end
    77         return dump(tab, "", "", 0);
    78     else
    79         return tostring(tab);
    80     end
    81 end
    View Code

    核心方法说明

    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: 
    %s", string.rep("    ", level+1), key, dump(v, key, space, level + 1)));
                else
                    table.insert(temp, string.format("%s%s: %s (loop)", string.rep("    ", level+1), key, tostring(v)));
                end
            else
                table.insert(temp, string.format("%s%s: %s", string.rep("    ", level+1), key, tostring(v)));
            end
        end
        table.insert(temp, string.format("%s}", string.rep("    ", level)));
        return table.concat(temp, string.format("%s
    ", space));
    end

    测试:

    tab = {1, 2, 3, 4, {5, 6, 7, 8}}
    -- 这里的node1就是上面贴出的双向链表
    print (TabToStr("node1", node1, true))
    print (TabToStr("node1", node1))
    print (TabToStr(tab))

    结果:

  • 相关阅读:
    webapi 中使用 protobuf
    apache httpclient cache 实现可缓存的http客户端
    编译nginx时提示undefined reference to 'pcre_free_study' 的问题及解决
    深入理解JVM内存回收机制(不包含垃圾收集器)
    从JDK源码理解java引用
    Buffer的创建及使用源码分析——ByteBuffer为例
    二叉树的子结构、深度以及重建二叉树
    数据结构——树与二叉树的遍历
    Java NIO之Buffer的使用
    Java多线程之synchronized详解
  • 原文地址:https://www.cnblogs.com/yougoo/p/11918508.html
Copyright © 2011-2022 走看看