表的Lua 4“n”属性

问题描述 投票:1回答:2

在Lua 4中,许多表都有一个“n”属性,用于跟踪表中的项目数。

所有表都有这个属性吗?它可以被覆盖吗?

我问,因为我正在尝试开发一个例程,以有效的Lua语法递归打印所有表的元素,并想知道从结果中过滤掉所有“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()
lua lua-table lua-4.0
2个回答
1
投票

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

有些函数使用它,比如tinsert()和其他表函数:

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

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

Lua 4.x --> Lua 5.x equivalent:
getn(tbl)       #tbl
tinsert(tbl,e)  table.insert(tbl,e)  or   tbl:insert(e)

当然,您仍然可以使用简单的表访问在表中添加元素。但是因为n非常有用,所以尽量保持更新。

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

如果表中不存在n但代码需要某个地方,则可以使用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将给出表中元素的数量,包括n。这里tbl.n的结果是10.因为最终我们不希望n被计为表的真实元素(这是),但只计算其他元素,我们应该初始化n到-1。

注2:这里使用了Lua 4.x upvalue运算符%,因为在foreach循环的函数(不在范围内)中无法访问tbl变量。可以使用%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变量实际上包含对表的引用,因此引用的表可以修改,因此可以毫无问题地更改元素n(以及表的其他元素)。

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

注3:可以使用全局变量tbl,但总是使用局部变量是一种好习惯。访问本地变量也比全局更快。


1
投票

并非所有表都具有此属性。它可以被覆盖。

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

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

语句表遍历给定表的所有对(索引,值)。它具有以下语法:

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

一个for语句就像

for index, value in exp do block end

相当于代码:

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

请注意以下事项:

  • _t是一个不可见的变量。此处的名称仅供参考。
  • 如果您在块内分配索引,则行为未定义。
  • 如果在遍历期间更改表_t,则行为未定义。
  • 变量index和value是语句的本地变量;你不能在结束后使用他们的价值观。
  • 您可以使用break来退出for。如果需要索引或值的值,请在断开之前将它们分配给其他变量。
  • 遍历表元素的顺序是未定义的,即使对于数字索引也是如此。如果要按数字顺序遍历索引,请使用数字。

请参阅Lua手册4.4.4

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

© www.soinside.com 2019 - 2024. All rights reserved.