如果 __index 未在元表中实现,则尝试调用 nil 值(方法 '...')

attempt to call a nil value (method '...') if __index not implemented in metatable

Lua 没有提供一种独特的 OOP 方式。

使用 setmetatable 可以有很多选择。

这是我尝试过的:

Person={}

function Person.__call(cls,name)
    return setmetatable({name=name},cls)
end

function Person:say(what)
    print(self.name..'> '..what)
end

setmetatable(Person,Person)

p=Person('Fred')
p:say('hello') -- 18

给出错误:

18: attempt to call a nil value (method 'say')

我可以加:

function Person.__index(cls,k)
    return Person[k]
end

然后上面的代码可以正常工作,但是我不明白为什么当 Person 本身已经是元表时找不到该方法。

您需要实现 __index 元值才能中继索引访问操作。仅有一个 metatable 是不够的。

另请注意,建议在将 table 用作元table 之前实现所有元方法。

参考Lua 5.4 Reference Manual 2.4 Metatables and Metamethods

__index: The indexing access operation table[key]. This event happens when table is not a table or when key is not present in table. The metavalue is looked up in the metatable of table.

The metavalue for this event can be either a function, a table, or any value with an __index metavalue. If it is a function, it is called with table and key as arguments, and the result of the call (adjusted to one value) is the result of the operation. Otherwise, the final result is the result of indexing this metavalue with key. This indexing is regular, not raw, and therefore can trigger another __index metavalue.

__index 就是那个元值。因此,如果您不提供该元值,Lua 应该做什么?

在下面的例子中元值是Person。 所以当我调用a:sayName()时,Lua会发现a.sayName是nil。它将检查 a 的元 table Person 中是否存在 __index 元值。有,在这种情况下,它是一个名为 Person 的 table,因此它将使用键 "sayName" 索引该人,从而导致以下函数调用:Person["sayName"](a)

local Person= {}
Person.__index = Person

setmetatable(Person, {
  __call = function (cls, ...)
    return cls:_init(...)
  end,
})

function Person:_init(name)
  local o= setmetatable({}, self)
  o.name = name
  return o
end

function Person:sayName()
  print(self.name)
end

local a = Person("Lisa")

a:sayName()