【问题标题】:Lua Metatable InconsistencyLua 元表不一致
【发布时间】:2013-05-05 18:34:41
【问题描述】:

我无法理解为什么 __index 元方法的行为在这些示例之间存在差异:

A = { __index = A }   
function A:speak()
    print("I'm an A")
end
An_A = setmetatable({},A)
An_A:speak()

将引发以下错误:lua: l.lua:8: attempt to call method 'speak' (a nil value)

虽然

B = { __index = function(t,key)  return B[key] end }
function B:speak()
    print("I'm an B")
end
An_B = setmetatable({},B)
An_B:speak()

将按预期执行,输出I'm an B


为了理解为什么会这样,我阅读了 PiL 的 this 部分。它指出:

使用 __index 元方法进行继承是如此普遍,以至于 Lua 提供了一个快捷方式。尽管有这个名字,__index 元方法确实 不需要是一个函数:它可以是一个表,而不是。当它是一个 函数,Lua 用表和缺席键作为它的调用它 论据。 当它是一个表时,Lua 会重做对该表的访问。

我对此的理解是,在涉及“A”的 sn-p 中,__index = A 导致在表A 中完成访问(根据上述引用的粗体部分)。如果是这种情况,我不明白为什么找不到与键 "speak" 关联的函数。为了尝试解决这个问题,我决定在B sn-p 中实现函数方法,它返回与B 中的key 关联的值,并且它起作用了。当然__index = A 和(改编自B__index = function(t,key) return A[key] end 具有相同的效果。

任何澄清将不胜感激。

【问题讨论】:

    标签: lua lua-table metatable


    【解决方案1】:

    在您的第一个示例中发生的是A.__index == nil。当您在此处的第一行创建“A”时:

    A = { __index = A }
    

    赋值“A”的右侧计算结果为nil,因为此时它还不存在。结果,稍后当您在此处设置元表时:

    An_A = setmetatable({},A)
    

    它真的会做类似这样的事情:

    An_A = setmetatable({}, {__index = nil} )
    

    要让它按您想要的方式工作,您必须确保 __index 不是 nil。比如建表后赋值:

    A = {}
    A.__index = A
    
    function A:speak()
      print("I'm an A")
    end
    An_A = setmetatable({},A)
    An_A:speak()              --> outputs I'm an A
    

    【讨论】:

    • 感谢您的精彩解释,我没想到会发生这种情况,我原以为它会像其他一些语言一样,其中f = lambda n: f(n) 是有效的。干杯:)
    • @HennyH: f = function(n) return f(n) end 出于同样的原因在 lua 中很好。等效的失败python是d = {"__index": d},但python会NameError
    • @Eric 我想任何递归函数都遵循相同的模式。
    • 如果您将__index 设置为访问A 的函数(类似于您的python 示例,而不是直接使用A),它实际上会起作用:A = { __index = function(t,k) return A[k] end }。因为该函数在调用时会按名称查找 A,到那时它将具有正确的值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-30
    • 2018-06-01
    • 2022-06-14
    • 1970-01-01
    • 1970-01-01
    • 2020-09-08
    相关资源
    最近更新 更多