Lua 4 "n" 属性 个表格

Lua 4 "n" property of tables

在 Lua 4 中,许多 table 都有一个 "n" 属性,它跟踪 table 中的项目数。

是否所有 table 都有这个 属性? 可以覆盖吗?

我问,因为我正在尝试开发一个以有效的 Lua 语法递归打印所有 table 元素的例程,并且想知道过滤所有元素是否安全"n" 个结果?

谢谢。

[编辑]

这是脚本:

-- ThoughtDump v1.4.0
-- Updated: 2017/07/25
-- *****************
-- Created by Thought (http://hw2.tproc.org)
-- Updated by Mikali

-- DESCRIPTION
-- ***********
-- Parses the globals table and __TDPrints its contents to "HW2.log".
-- Can also be used to parse (i.e., pretty-print) generic tables in some cases.

-- Note: functions & variables must actually be declared in order to be parsed. 
-- Otherwise, they are ignored.
-- Note: if parsing a table other than the globals table, the __TDPrinted table
-- values may be in a different order than was originally written. Values with 
-- numerical indices are moved to the "top" of the table, followed by values 
-- with string indices, followed by tables. Functions appear in different 
-- locations, depending on whether they are indexed using a number or a string.
-- Note: despite the fact that nil values cannot be stored in tables, they are 
-- still handled.
-- Note: even though functions may be referenced within tables, a function will 
-- only be parsed correctly if it is indexed using a string that is the same as
-- the name of the function.

__TDOutputString = ""

function __TDParse(name, value, level, verbose, numbers, collapse)
    if ((name == "__TDParse") or (name == "__TDSortHash") or (name == "__TDPrint") or (name == "__TDPrintGlobals()") or (name == "__TDOutputString")) then
        return
    end
    local Element = nil
    local ValType = type(value)
    local NamType = type(name)
    local PreLevel = ""
    if (collapse == 0) then
        for i = 1, level do
            PreLevel = PreLevel .. "\t"
        end
    end
    local ComLevel = ""
    if (level ~= 0) then
        ComLevel = ","
    end
    if ((ValType == "function") or (ValType == "userdata")) then
        if (NamType == "string") then
            Element = PreLevel .. name .. " = " .. name .. ComLevel
        elseif (numbers == 1) then
            Element = PreLevel .. "[" .. name .. "] = " .. name .. ComLevel
        else
            Element = PreLevel .. name .. ComLevel
        end
    elseif (ValType == "string") then
        if (NamType == "string") then
            Element = PreLevel .. name .. " = \"" .. value .. "\"" .. ComLevel
        elseif (numbers == 1) then
            Element = PreLevel .. "[" .. name .. "] = \"" .. value .. "\"" .. ComLevel
        else
            Element = PreLevel .. "\"" .. value .. "\"" .. ComLevel
        end
    elseif (ValType == "number") then
        if (NamType == "string") then
            Element = PreLevel .. name .. " = " .. value .. ComLevel
        elseif (numbers == 1) then
            Element = PreLevel .. "[" .. name .. "] = " .. value .. ComLevel
        else
            Element = PreLevel .. value .. ComLevel
        end
    elseif (ValType == "table") then
        if (NamType == "string") then
            Element = PreLevel .. name .. " ="
        elseif (numbers == 1) then
            Element = PreLevel .. "[" .. name .. "] ="
        else
            Element = ""
        end
    elseif (ValType == "nil") then
        if (NamType == "string") then
            Element = PreLevel .. name .. " = nil" .. ComLevel
        elseif (numbers == 1) then
            Element = PreLevel .. "[" .. name .. "] = nil" .. ComLevel
        else
            Element = PreLevel .. "nil" .. ComLevel
        end
    else
        Element = PreLevel .. "-- unknown object type " .. ValType .. " for object " .. name
    end
    if (verbose == 1) then
        Element = Element .. "  -- " .. ValType .. ", tag: " .. tag(value)
    end
    if (((ValType == "table") and (NamType == "number") and (numbers == 0)) or (collapse == 1)) then
        __TDPrint(Element, 0)
    else
        __TDPrint(Element, 1)
    end
    if (ValType == "table") then
        __TDPrint(PreLevel .. "{", collapse == 0)
        __TDSortHash(__TDParse, value, level + 1, verbose, numbers, collapse)
        __TDPrint(PreLevel .. "}" .. ComLevel, 1)
    end
end

function __TDSortHash(func, tabl, level, verbose, numbers, collapse)
    local typesarray = {}
    local typescount = {}
    local keycount = 1
    local keyarray = {}
    for i, iCount in tabl do
        local thistype = type(iCount)
        if not (typesarray[thistype]) then
            typescount[thistype] = 0
            typesarray[thistype] = {}
        end
        typescount[thistype] = typescount[thistype] + 1
        typesarray[thistype][typescount[thistype]] = i
    end
    sort(typesarray)
    for i, iCount in typesarray do
        sort(iCount)
        for j, jCount in iCount do
            keyarray[keycount] = tostring(jCount)
            keycount = keycount + 1
        end
    end
    for i, iCount in keyarray do
        local tempcount = tonumber(iCount)
        if (tempcount) then
            iCount = tempcount
        end
        func(iCount, tabl[iCount], level, verbose, numbers, collapse)
    end
end

function __TDPrint(instring, newline)
    __TDOutputString = __TDOutputString .. instring
    if (newline == 1) then
        __TDOutputString = __TDOutputString .. "\n"
    end
end

function __TDPrintGlobals()
    __TDOutputString = ""
    __TDPrint("globals =", 1)
    __TDPrint("{", 1)
    __TDSortHash(__TDParse, globals(), 1, 0, 0, 0)
    __TDPrint("}\n", 1)
    local WriteFile = "$test_globals_write.lua"
    writeto(WriteFile)
    write(__TDOutputString)
    writeto()
end

__TDPrintGlobals()

并非所有 table 都有此 属性。 可以覆盖。

为什么不使用 for 循环遍历 table?或者如果可能,使用 Lua 5.3 ;)

在 Lua 中,这被称为 table for 循环,在现代 Lua 中,它被称为通用 for 循环。

The table for statement traverses all pairs (index,value) of a given table. It has the following syntax:

stat ::= for name `,' name in exp1 do block end

A for statement like

for index, value in exp do block end

is equivalent to the code:

do
  local _t = exp
  local index, value = next(t, nil)
  while index do
      block
      index, value = next(t, index)
     end
  end

Note the following:

  • _t is an invisible variable. The name is here for explanatory purposes only.

  • The behavior is undefined if you assign to index inside the block.

  • The behavior is undefined if you change the table _t during the traversal.

  • The variables index and value are local to the statement; you cannot use their values after the for ends.

  • You can use break to exit a for. If you need the value of index or value, assign them to other variables before breaking.

  • The order that table elements are traversed is undefined, even for numerical indices. If you want to traverse indices in numerical order, use a numerical for.

参考Lua手册4.4.4

https://www.lua.org/manual/4.0/manual.html#4.4

In Lua 4.x in tables,n 只是 table 的一个元素,就像 table 可以包含的任何其他元素一样,但是它不是 table 机制本身的一部分。 因此,它可以被覆盖或删除。

一些函数使用它,如 tinsert() 和其他 table 函数:

local tbl = { n=0 }
tinsert(tbl, 123)
print(tbl.n)      --> 1

这非常有用,因为 getn() 函数仅给出 table 的最高数字索引。但是,如果 table 中只有命名元素或混合索引和命名索引,则 getn() 不会反映 table 中元素的真实数量。如果始终使用 table 函数(如 tinsert())插入(或删除)元素,则 n 是 table.

中元素的准确数量
Lua 4.x --> Lua 5.x equivalent:
getn(tbl)       #tbl
tinsert(tbl,e)  table.insert(tbl,e)  or   tbl:insert(e)

当然,您仍然可以使用简单的 table 访问在 table 中添加元素。但由于 n 可能非常有用,请尽量保持更新。

tbl["Bla"] = 234   
tbl.Bli = 345
tbl.n = tbl.n + 2

如果 n 在 table 中不存在但某处的代码需要它,可以使用 for 循环添加它:

local tbl = {1,2,3,4,5,6}; tbl.a=11; tbl.b=22; tbl.c=33
local n = 0
for ie, e in tbl do
   n = n + 1
end
tbl.n = n

或 foreach 循环:

local tbl = {1,2,3,4,5,6}; tbl.a=11; tbl.b=22; tbl.c=33
tbl.n = 0
foreach(tbl, function() %tbl.n = %tbl.n + 1 end )

注1:tbl.n初始化为0会给出table中的元素个数,包括n。这里 tbl.n 的结果是 10。 由于最终我们不希望 n 被算作 table 的真实元素(这是),而是只计算其他元素,我们应该将 n 初始化为 -1 然后。

注意 2:这里使用 Lua 4.x 上值运算符 % 是因为 tbl 变量在 foreach 循环的函数中(不在范围内)不可访问。它可以使用 %tbl 到达。但是,upvalue 始终是只读的,因此无法更改 tbl 变量。以下将在函数中产生错误:

%tbl = { }  -- change the reference to another table
%tbl = 135  -- change the ref to the table for a number (or a string, ...)

由于 tbl 变量实际上包含对 table 的引用,所引用的 table 可以修改,因此元素 n 可以毫无问题地更改(以及 table 的其他元素=43=]).

%tbl.n = %tbl.n + 1   -- increment the element n of the referenced table

注意 3:可以使用全局变量 tbl,但最好始终使用局部变量。访问局部变量也比全局变量快。