我已经实现了自己的班级系统,我遇到了__tostring
的问题;我怀疑其他metamethods也会发生类似的问题,但我还没有尝试过。
(简要介绍:每个类都有__classDict
属性,包含所有方法。它用作类实例'__index
。同时,__ classDict的__index
是超类'__classDict
,因此可以自动查找超类中的方法。)
我希望在所有实例中都有“默认的tostring”行为。但它不起作用:“tostring”行为不会正确地“传播”通过子类。
我已完成此测试,例证我的问题:
mt1 = {__tostring=function(x) return x.name or "no name" end }
mt2 = {}
setmetatable(mt2, {__index=mt1})
x = {name='x'}
y = {name='y'}
setmetatable(x, mt1)
setmetatable(y, mt2)
print(x) -- prints "x"
print(mt2.__tostring(y)) -- prints "y"
print(y) -- prints "table: 0x9e84c18" !!
我宁愿让最后一行打印“y”。
Lua的“to_String”行为必须使用等效的
rawget(instance.class.__classDict, '__tostring')
而不是相当于
instance.class.__classDict.__tostring
我怀疑所有metamethods都会发生同样的事情; rawget
- 使用等效操作。
我想我可以做的一件事就是在我进行子类化时复制所有的元方法(上面的例子中的等价物将是mt2.__tostring = mt1.__tostring
),但这有点不雅。
有没有人为这类问题而战?您的解决方案在哪里?
答案 0 :(得分:3)
我怀疑所有metamethods都会发生同样的事情;使用rawget等效操作。
这是正确的。 来自lua手册:
...应该被理解为
rawget(getmetatable(obj) or {}, event)
。也就是说,对元方法的访问不会调用其他元方法,并且对没有元表的对象的访问不会失败(它只会导致nil)。
通常每个类都有自己的元表,并将所有对函数的引用复制到其中。
也就是说,mt2.__tostring = mt1.__tosting
答案 1 :(得分:1)
答案 2 :(得分:0)
根据我对Lua 5.1的经验,使用rawget()在元数据中查找元方法,这就是必须将对函数的引用复制到您创建的每个类表中的原因。
答案 3 :(得分:-1)
请参阅Lua Users Wiki上的Inheritance Tutorial。