在 Lua 中,您通常不能像调用函数那样调用表。例如,此代码将产生“尝试调用本地't'(表值)”的错误。
local t = {}
t()
但是,有一种方法可以通过使用元表来完成这项工作。
local hello = {}
local mt = {} -- The metatable
mt.__call = function ()
print("Hello!")
end
setmetatable(hello, mt)
hello() -- prints "Hello!"
当你尝试像调用函数一样调用表时,Lua 首先检查表是否有元表。如果是这样,那么它会尝试调用该__call
元表属性中的函数。函数的第一个参数__call
是表本身,随后的参数是当表作为函数调用时传递的参数。如果表没有元表,或者元表没有__call
函数,则会引发“尝试调用本地 't'”错误。
您的示例代码存在三个问题:
- 您正在尝试使用
__init
而不是__call
. Lua 没有__init
元方法。
__call
采用与您正在使用的参数不同的参数。该__call
函数的第一个参数是表本身。您可以使用function MyClass.__call(self, tab)
,也可以使用冒号语法 ,function MyClass:__call(tab)
它会为您隐式添加self
参数。这两种语法在功能上是相同的。
- 您尚未为表设置元
MyClass
表。当您为 MyClass 的对象设置元表时,这并不意味着会自动为 MyClass 本身设置元表。
要解决此问题,您可以执行以下操作:
local MyClass = {}
setmetatable(MyClass, MyClass)
MyClass.__index = MyClass
function MyClass:__call(tab)
local obj = {}
obj.tab = tab or {}
setmetatable(obj, MyClass)
return obj
end
return MyClass
这将 MyClass 设置为将自己用作元表,这是完全有效的 Lua。
元表系统非常灵活,允许您拥有几乎任何您想要的类/对象方案。例如,如果您愿意,您可以内联执行所有操作。
local MyClass = {}
setmetatable(MyClass, {
__call = function (class, tab)
local obj = {}
obj.tab = tab or {}
setmetatable(obj, {
__index = MyClass
})
return obj
end
})
return MyClass
除了简洁之外,这还有一个优点,即如果人们可以访问类表,他们就不能更改类的元方法。