在Lua中,元方法的继承
我非常喜欢“Lua编程”16.1, 16.2中描述面向对象编程的方式:http://www.lua.org/pil/16.1.html,http://www.lua.org/pil/16.2.html,并且想要遵循这个方法。但是我想进一步发展一下:我想要一个名为“class”的基础“类”,它应该是所有子类的基础,因为我想在那里实现一些帮助方法(比如“instanceof”等),但本质上应该像书中描述的那样:
function class:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
现在我的问题是:
我想要一个从“class”继承的“number”类:
number = class:new()
我想要在这个类中定义运算符重载的元方法(例如 __add,__sub等),所以下面的代码段将能够正常工作:
n1 = number:new()
n2 = number:new()
print(n1 + n2)
这不是个问题。但是,现在我想要一个第三个类“money”,它从“number”继承:
money = number:new{value=10,currency='EUR'}
我在这里引入了一些新属性等。
我的问题是,我不能让“money”继承“class”和“number”中定义的所有元方法,包括“number”中定义的所有元方法。
我尝试了几种方法,例如重写“new”或修改元表,但我无法让他们正常工作,或者在“money”中丢失“class”的方法或在“money”中丢失“number”的元方法。
我知道有很多类的实现方法,但我真的很想坚持Lua本身的最简方法。
非常感谢您的帮助!
原文链接 https://stackoverflow.com/questions/4155842
我做了类似的事情并且遇到了相似的问题。下面是我的基类定义:
RootObjectType = {}
RootObjectType.__index = RootObjectType
function RootObjectType.new( o )
o = o or {}
setmetatable( o, RootObjectType )
o.myOid = RootObjectType.next_oid()
return o
end
function RootObjectType.newSubclass()
local o = {}
o.__index = o
setmetatable( o, RootObjectType )
RootObjectType.copyDownMetaMethods( o, RootObjectType )
o.baseClass = RootObjectType
return o
end
function RootObjectType.copyDownMetaMethods( destination, source ) -- 这是你需要的代码
destination.__lt = source.__lt
destination.__le = source.__le
destination.__eq = source.__eq
destination.__tostring = source.__tostring
end
RootObjectType.myNextOid = 0
function RootObjectType.next_oid()
local id = RootObjectType.myNextOid
RootObjectType.myNextOid = RootObjectType.myNextOid + 1
return id
end
function RootObjectType:instanceOf( parentObjectType )
if parentObjectType == nil then return nil end
local obj = self
--while true do
do
local mt = getmetatable( obj )
if mt == parentObjectType then
return self
elseif mt == nil then
return nil
elseif mt == obj then
return nil
else
obj = mt
end
end
return nil
end
function RootObjectType:__lt( rhs )
return self.myOid < rhs.myOid
end
function RootObjectType:__eq( rhs )
return self.myOid == rhs.myOid
end
function RootObjectType:__le( rhs )
return self.myOid <= rhs.myOid
end
function RootObjectType.assertIdentity( obj, base_type )
if obj == nil or obj.instanceOf == nil or not obj:instanceOf( base_type ) then
error( "Identity of object was not valid" )
end
return obj
end
function set_iterator( set )
local it, state, start = pairs( set )
return function(...)
local v = it(...)
return v
end, state, start
end
这个问题已经有答案了,但是让我来介绍一下我遇到的这个问题时的解决方案,当时我正在开发我的 OOP lib middleclass。
对于这个问题,我开始列出了所有 "有用" 的元方法名称的列表:
local _metamethods = { -- 所有的元方法除了 __index
'__add', '__call', '__concat', '__div', '__le', '__lt', '__mod', '__mul', '__pow', '__sub', '__tostring', '__unm'
}
我使用这个列表来为创建的每个类添加方法。因此,实际上,我有了所有元方法的 "默认实现":
-- 创建一个子类
function Object.subclass(theClass, name)
...
local dict = theSubClass.__classDict -- classDict 包含所有的[元]方法
local superDict = theSuperClass.__classDict -- 超类也是如此
...
for _,mmName in ipairs(_metamethods) do -- 创建初始的元方法
dict[mmName]= function(...) -- 默认情况下,它们只是去查找一个实现
local method = superDict[mmName] -- 如果没有找到,它们就抛出一个错误
assert( type(method)=='function', tostring(theSubClass) .. " doesn't implement metamethod '" .. mmName .. "'" )
return method(...)
end
end
诀窍就在于默认实现 "调用" 父类的实现;如果不存在,它会抛出一个错误。
以这种方式实现的元方法只比常规方法稍慢一些(多2个方法调用),并且使用的内存量非常小(每个类多12个函数)。
附:我没有包括 __len
元方法,因为 Lua 5.1 无论如何都不会尊重它。
附2:我也没有包括 __index
或 __newindex
,因为我必须在我的类内部使用它们。
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
我认为你遇到的问题是由于操作符元方法是使用类似于
rawget(getmetatable(obj) or {}, "__add")
查找的。因此,这些运算符不会随其他函数一起继承。我曾经尝试了这个方法,即让
new
函数像这样复制运算符:function class:new(o) o = o or {} setmetatable(o, self) self.__index = self local m=getmetatable(self) if m then for k,v in pairs(m) do if not rawget(self,k) and k:match("^__") then self[k] = m[k] end end end return o end