【问题标题】:What is the difference with tables and their subtables in setting them to nil in Lua?在 Lua 中将表及其子表设置为 nil 有什么区别?
【发布时间】:2019-08-17 23:56:18
【问题描述】:

我知道 Lua 会在内存中保留一个表,只要在代码中的某处仍然存在对它的引用,这意味着您不能通过将表作为参数传递给函数来将它们设置为 nil。但是,我不明白为什么您可以对子表执行此操作。

local a = {}
a.b = {}

local function remove( t )
    t.b = nil
    t = nil
end

remove( a )

print( a and a.b, a )

在将 a 作为参数传递给函数 remove 之后,我将参数及其子表设置为 nil。由于上述原因,我知道这不应该将 a 设置为 nil,但是有人可以告诉我为什么 a.b 可以设置为 nil,即使我的理解,它仍然应该从外部引用它,就像 a 一样。

【问题讨论】:

    标签: lua


    【解决方案1】:

    我知道 Lua 会在内存中保留一个表,只要在代码中的某处仍然存在对它的引用,

    是的,但这实际上意味着我们不必担心内存管理。我们通常不会考虑何时对表进行垃圾收集,除非我们的内存非常紧张并且必须调整垃圾收集器。对于正常使用,我们可以假设一旦我们失去对它的最后一次引用,表就会从内存中删除。

    这意味着您不能通过将表作为参数传递给函数来将它们设置为 nil。

    这并不是真正的原因。表和 nil 是两种不同的数据类型,因此您不能从字面上将表设置为 nil。通常我们所说的“将表设置为 nil”的意思是获取引用表的变量或表键,并将该变量/键设置为 nil。这可能是也可能不是我们对该表的最后一个引用。

    函数不能设置参数变量的原因是参数(函数的局部变量)和用作参数的变量是两个完全不同的变量。

    但是有人可以告诉我为什么 a.b 可以设置为 nil,尽管根据我的理解,它仍然应该从外部引用它,就像使用 a 一样。

    不,表a.b 没有外部引用。没有引用该表的局部变量。表键没有变量的作用域。对该表的唯一引用是在表 a 内部,它被语句 t.b = nil 修改。

    t.b = nil 语句有效,因为它修改了 t,不止一个变量引用该表。 't = nil' 分配给 变量 t,它基本上与任何其他变量无关。

    【讨论】:

    • 很好的解释。 “用作参数的变量”:是的,参数就是表达式。作为变量的表达式是一种特殊情况,但一点也不特殊。调用者被传递了表达式的值。它不会知道价值的来源。
    【解决方案2】:

    严格来说,您不是“将a.b 设置为nil”。描述t.bil = nil 所做工作的准确方式是

    “将值nil与表a中的键"b"相关联”

    例如,将您写的内容与以下内容进行比较:

    local o = {}
    o[1] = "one"
    o[2] = "two"
    o[3] = "three"
    
    -- o currently looks like
    --  KEY | VALUE
    -- -----+--------
    --    1 | "one"
    --    2 | "two"
    --    3 | "three"
    
    
    o[2] = nil
    
    -- o now looks like
    --  KEY | VALUE
    -- -----+--------
    --    1 | "one"
    --    3 | "three"
    

    这很明显不是“将数字2 设置为零”。这只是修改表o内容,不再将键2 与任何值关联。

    回顾一下你最初询问的代码:

    local alpha = {}
    local beta = {}
    
    alpha[1] = "one"
    alpha[2] = beta
    alpha[3] = "three"
    
    -- alpha now looks like
    --  KEY | VALUE
    -- -----+--------
    --    1 | "one"
    --    2 | <beta>
    --    3 | "three"
    
    alpha[2] = nil
    
    -- alpha now looks like
    --  KEY | VALUE
    -- -----+--------
    --    1 | "one"
    --    3 | "three"
    

    同样,beta 不会以任何方式被修改,数字2 也不会被修改。只是,2 与值beta 的关联已从表alpha 的内容中删除。

    【讨论】:

    • 在您的代码中,local beta = {}; alpha[2] = beta; alpha[2] = nil; 这会将对 beta 的引用设置为 nil,但实际上并未将 beta(表)设置为 nil。我明白了。但是,在我的代码中,由于子表 a.b 被分配了 nil 值并且不再可访问,那么它与 nil 不一样并且不会被垃圾收集吗?或者它会保留为表的一部分,但以不可访问的方式,直到它所属的表最终正确设置为 nil?
    • 你的代码就是这样的。 .b 就像 [2]
    • a.b 在您的初始代码中不是表的一些特殊“家”。隐含地创建了一个“局部”变量来保存{},然后将该局部变量放入a 中的键b 中,如图所示。
    猜你喜欢
    • 2016-08-15
    • 1970-01-01
    • 2019-02-11
    • 2020-05-12
    • 2011-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多