Lua 中将表及其子表设置为 nil 的区别是什么?

我知道 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 一样在外部保有一个引用。

点赞
用户2616735
用户2616735

严格来说,你并不是在“将 a.b 设为 nil”。描述 t.bil = nil 的确切方法是,“将键为“b”的值nil与表a关联”。

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

local o = {}
o[1] = "one"
o[2] = "two"
o[3] = "three"

-- o 目前看起来像这样
--  KEY | VALUE
-- -----+--------
--    1 | "one"
--    2 | "two"
--    3 | "three"

o[2] = nil

-- o 现在看起来像这样
--  KEY | VALUE
-- -----+--------
--    1 | "one"
--    3 | "three"

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

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

local alpha = {}
local beta = {}

alpha[1] = "one"
alpha[2] = beta
alpha[3] = "three"

-- alpha 现在看起来像这样
--  KEY | VALUE
-- -----+--------
--    1 | "one"
--    2 | <beta>
--    3 | "three"

alpha[2] = nil

-- alpha 现在看起来像这样
--  KEY | VALUE
-- -----+--------
--    1 | "one"
--    3 | "three"

同样,beta没有以任何方式被修改,数字2也没有被修改。仅仅是从表alpha的内容中删除了将2与值beta关联的内容。

2019-08-18 02:19:22
用户3574628
用户3574628

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

是的,但这只意味着我们不必担心内存管理。除非我们真的在内存上很紧,而必须调整垃圾收集器,否则我们通常不需要考虑何时清除表。在正常使用中,我们可以假设只要失去对其的最后一个引用,表就会从内存中删除。

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

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

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

但是,有谁能告诉我为什么可以将a.b设置为nil,即使在我理解范围外时,它仍然应该具有对它的引用,就像a一样。

不,表a.b并没有外部引用。没有引用那个表的本地变量。表键没有变量那样的作用域。对该表的唯一引用是在表a内部,该引用会通过语句't.b = nil'进行修改。

语句't.b = nil'可行是因为它修改了多个变量都有的_table_t。't = nil'则将其分配给单独一个变量't',与其他任何变量基本上没有关系。

2019-08-18 04:57:43