如何在Lua中创建一个简单的可导入类?

时间:2017-05-22 18:44:14

标签: lua lua-table meta-method

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

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中编写类,但我不认为我理解了这些差异,因此在实现细节中迷失了方向。是否有或多或少的传统的方式?

2 个答案:

答案 0 :(得分: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首先检查表是否具有元表。如果是,则尝试在该metatable的__call属性中调用该函数。 __call函数的第一个参数是表本身,后续参数是表作为函数调用时传递的参数。如果表格没有metatable,或者metatable没有__call功能,那么"尝试呼叫本地''""""""""""""""""" ;提出错误。

您的示例代码有三个问题:

  1. 您正尝试使用__init代替__call。 Lua没有__init metamethod。
  2. __call采用的参数与您使用的参数不同。 __call函数的第一个参数是表本身。您可以使用function MyClass.__call(self, tab),也可以使用冒号语法function MyClass:__call(tab),它会为您隐式添加self参数。这两种语法功能相同。
  3. 您还没有为MyClass表设置元表。在为MyClass的对象设置元表时,这并不意味着会自动为MyClass本身设置元表。
  4. 要解决此问题,您可以执行以下操作:

    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设置为metatable,这是完全有效的Lua。

    metatables系统非常灵活,允许您拥有所需的任何类/对象方案。例如,如果您愿意,您可以内联完成所有操作。

    local MyClass = {}
    
    setmetatable(MyClass, {
        __call = function (class, tab)
            local obj = {}
            obj.tab = tab or {}
            setmetatable(obj, {
                __index = MyClass
            })
            return obj
        end
    })
    
    return MyClass
    

    除了简洁之外,这还有一个好处,即如果他们可以访问班级表,人们就无法改变班级的元方法。

答案 1 :(得分: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