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