3

我想MyClass在 Lua 中创建一个单独的文件myclass.lua中的类,我可以稍后导入和使用。它应该按以下方式工作:

local MyClass = require 'myclass'
tab = {1,2,3}
m = MyClass(tab)

但是,按照 Lua 文档中的代码,我无法使其工作并且遇到错误attempt to call global 'MyClass' (a table value)

到目前为止我为myclass.lua编写的代码:

local MyClass = {}
MyClass.__index = MyClass

function MyClass.__init(tab)
    self.tab = tab or {}
    setmetatable({},MyClass)
    return self
end
return MyClass

有很多示例如何在 Lua 中编写类,但我认为我不了解其中的区别,因此迷失在实现细节中。有或多或少的传统方法吗?

4

2 回答 2

1

在 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'”错误。

您的示例代码存在三个问题:

  1. 您正在尝试使用__init而不是__call. Lua 没有__init元方法。
  2. __call采用与您正在使用的参数不同的参数。该__call函数的第一个参数是表本身。您可以使用function MyClass.__call(self, tab),也可以使用冒号语法 ,function MyClass:__call(tab)它会为您隐式添加self参数。这两种语法在功能上是相同的。
  3. 您尚未为表设置元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

除了简洁之外,这还有一个优点,即如果人们可以访问类表,他们就不能更改类的元方法。

于 2017-05-23T04:59:50.627 回答
0

没有__init可用于表的元方法。当您执行以下操作时:

m = MyClass(tab)

它寻找MyClass.__call方法定义。只需将您的更新myclass.lua为:

local MyClass = {}
MyClass.__index = MyClass

function MyClass:__call(tab)
    self.tab = tab or {}
    setmetatable({},MyClass)
    return self
end

return MyClass
于 2017-05-22T19:07:02.053 回答