Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Class 如何在Lua中创建类、子类和属性?_Class_Lua - Fatal编程技术网

Class 如何在Lua中创建类、子类和属性?

Class 如何在Lua中创建类、子类和属性?,class,lua,Class,Lua,我很难在课堂上摸索。毫无结果的谷歌搜索让我想到了元表,并暗示第三方库是模拟/编写类所必需的 下面是一个示例(因为我注意到,当我提供示例代码时,我得到了更好的答案): 这是我第一次尝试用Javier建议的技巧来翻译上面的内容 我接受了RBerteig的建议。然而,对派生类的调用仍然会产生:“尝试调用方法‘methodName’(一个nil值)” 有很多方法可以做到这一点,但我就是这样做的(通过对继承的尝试进行更新): 我不实现私有的、受保护的等等。在Lua中实现像OOP这样的类真的很容易;只需将所

我很难在课堂上摸索。毫无结果的谷歌搜索让我想到了元表,并暗示第三方库是模拟/编写类所必需的

下面是一个示例(因为我注意到,当我提供示例代码时,我得到了更好的答案):

这是我第一次尝试用Javier建议的技巧来翻译上面的内容

我接受了RBerteig的建议。然而,对派生类的调用仍然会产生:
“尝试调用方法‘methodName’(一个nil值)”


有很多方法可以做到这一点,但我就是这样做的(通过对继承的尝试进行更新):


我不实现私有的、受保护的等等。

在Lua中实现像OOP这样的类真的很容易;只需将所有“方法”放在元表的
\uu index
字段中:

local myClassMethods = {}
local my_mt = {__index=myClassMethods}

function myClassMethods:func1 (x, y)
    -- Do anything
    self.x = x + y
    self.y = y - x
end

............

function myClass ()
    return setmetatable ({x=0,y=0}, my_mt)
就我个人而言,我从来都不需要继承,所以以上这些对我来说已经足够了。如果还不够,可以为methods表设置元表:

local mySubClassMethods = setmetatable ({}, {__index=myClassMethods})
local my_mt = {__index=mySubClassMethods}

function mySubClassMethods:func2 (....)
    -- Whatever
end

function mySubClass ()
    return setmetatable ({....}, my_mt)
更新: 更新的代码中有错误:

Router = {};
mt_for_router = {__index=Router}
--Router inherits from ElectronicDevice
Router = setmetatable({},{__index=ElectronicDevice});
请注意,您初始化
路由器
,并由此为路由器构建
mt\u;但随后您将
Router
重新分配到一个新表,而
mt\u for\u Router
仍然指向原始的
Router


Router={}
替换为
Router=setmetatable({},{{uu index=ElectronicDevice})
(在
mtu for_Router
初始化之前)。

我喜欢的方式是实现clone()函数。
请注意,这是针对Lua5.0的。我认为5.1有更多内置的面向对象结构

clone = function(object, ...) 
    local ret = {}

    -- clone base class
    if type(object)=="table" then 
            for k,v in pairs(object) do 
                    if type(v) == "table" then
                            v = clone(v)
                    end
                    -- don't clone functions, just inherit them
                    if type(v) ~= "function" then
                            -- mix in other objects.
                            ret[k] = v
                    end
            end
    end
    -- set metatable to object
    setmetatable(ret, { __index = object })

    -- mix in tables
    for _,class in ipairs(arg) do
            for k,v in pairs(class) do 
                    if type(v) == "table" then
                            v = clone(v)
                    end
                    -- mix in v.
                    ret[k] = v
            end
    end

    return ret
end
然后将类定义为表:

Thing = {
   a = 1,
   b = 2,
   foo = function(self, x) 
     print("total = ", self.a + self.b + x)
   end
}
要实例化它或从中派生,可以使用clone(),可以通过将它们作为mix-ins传递到另一个表(或多个表)来重写它们

myThing = clone(Thing, { a = 5, b = 10 })
要调用,请使用以下语法:

myThing:foo(100);
将打印:

total = 115
要派生子类,基本上需要定义另一个原型对象:

BigThing = clone(Thing, { 
     -- and override stuff.  
     foo = function(self, x)
         print("hello");
     end
}

这个方法非常简单,可能太简单了,但对我的项目来说效果很好

您更新的代码很冗长,但应该可以正常工作除了,您的打字错误正在破坏其中一个元表:

--Modem inherits from ElectronicDevice Modem = setmetatable({},{__index,ElectronicDevice}); --调制解调器继承了电子设备 调制解调器=可设置元表({},{{uu索引,电子设备}); 应该读

--Modem inherits from ElectronicDevice Modem = setmetatable({},{__index=ElectronicDevice}); --调制解调器继承了电子设备 调制解调器=可设置元表({},{{uu索引=电子设备}); 现有的片段使
调制解调器
元表成为一个数组,其中第一个元素几乎肯定是零(通常的
\u G.\u索引值
,除非您使用
strict.lua
或类似的东西),第二个元素是
电子设备

在您对元表进行了更深入的研究之后,该描述将有意义。一件有帮助的事情是建立一个小的基础设施,使通常的模式更容易得到正确的


我还建议您阅读中有关OOP的章节。您还需要重新阅读关于表和元表的章节。另外,我已经链接到第一版的在线副本,但强烈建议拥有第二版的副本。书中还有几篇文章与此相关。也建议使用它。

下面是代码的文本转录示例,其中包含一个有用的
类,可以移动到另一个文件中

这绝不是
类的规范实现;您可以随意定义对象模型

Class = {}

function Class:new(super)
    local class, metatable, properties = {}, {}, {}
    class.metatable = metatable
    class.properties = properties

    function metatable:__index(key)
        local prop = properties[key]
        if prop then
            return prop.get(self)
        elseif class[key] ~= nil then
            return class[key]
        elseif super then
            return super.metatable.__index(self, key)
        else
            return nil
        end
    end

    function metatable:__newindex(key, value)
        local prop = properties[key]
        if prop then
            return prop.set(self, value)
        elseif super then
            return super.metatable.__newindex(self, key, value)
        else
            rawset(self, key, value)
        end
    end

    function class:new(...)
        local obj = setmetatable({}, self.metatable)
        if obj.__new then
            obj:__new(...)
        end
        return obj
    end

    return class
end

ElectronicDevice = Class:new()

function ElectronicDevice:__new()
    self.isOn = false
end

ElectronicDevice.properties.isOn = {}
function ElectronicDevice.properties.isOn:get()
    return self._isOn
end
function ElectronicDevice.properties.isOn:set(value)
    self._isOn = value
end

function ElectronicDevice:Reboot()
    self._isOn = false
    self:ResetHardware()
    self._isOn = true
end

Router = Class:new(ElectronicDevice)

Modem = Class:new(ElectronicDevice)

function Modem:WarDialNeighborhood(areaCode)
    local cisco = Router:new()
    cisco:Reboot()
    self:Reboot()
    if self._isOn then
        self:StartDialing(areaCode)
    end
end
如果坚持为属性获取/设置方法,则不需要
\uuuu index
\uuu newindex
函数,只需要一个
\uu index
表即可。在这种情况下,模拟继承的最简单方法如下:

BaseClass = {}
BaseClass.index = {}
BaseClass.metatable = {__index = BaseClass.index}

DerivedClass = {}
DerivedClass.index = setmetatable({}, {__index = BaseClass.index})
DerivedClass.metatable = {__index = DerivedClass.index}
换句话说,派生类的
\u索引
表“继承”基类的
\u索引
表。这是因为Lua在委托给
\u索引
表时,会有效地重复对该表的查找,因此会调用
\u索引
表的元方法


另外,在调用
obj.Method(…)
vs
obj:Method(…)
时要小心
obj:Method(…)
obj.Method(obj,…)
的语法糖,将这两个调用混合在一起会产生异常错误。

如果您不想重新发明轮子,有一个很好的Lua库实现了几个对象模型。它被称为。

另一种简单的子类方法

local super    = require("your base class")
local newclass = setmetatable( {}, {__index = super } )
local newclass_mt = { __index = newclass }

function newclass.new(...) -- constructor
    local self = super.new(...)
    return setmetatable( self, newclass_mt )
end
即使被覆盖,您仍然可以使用超类中的函数

function newclass:dostuff(...)
    super.dostuff(self,...)
   -- more code here --
end
将self传递给超类函数时,不要忘记使用一个点

阅读了吗?
BaseClass = {}
BaseClass.index = {}
BaseClass.metatable = {__index = BaseClass.index}

DerivedClass = {}
DerivedClass.index = setmetatable({}, {__index = BaseClass.index})
DerivedClass.metatable = {__index = DerivedClass.index}
local super    = require("your base class")
local newclass = setmetatable( {}, {__index = super } )
local newclass_mt = { __index = newclass }

function newclass.new(...) -- constructor
    local self = super.new(...)
    return setmetatable( self, newclass_mt )
end
function newclass:dostuff(...)
    super.dostuff(self,...)
   -- more code here --
end