Ruby 如何实施';可比';如果父类已经有一个'==';
我有一个库类,它提供了相等和不相等的方法。我从中派生出另一个类,与父类不同,它引入了排序关系,也就是说,请求派生类的两个元素是有意义的,哪一个更小。特别是,可以对派生类的对象数组进行排序 我的第一个方法是Ruby 如何实施';可比';如果父类已经有一个'==';,ruby,Ruby,我有一个库类,它提供了相等和不相等的方法。我从中派生出另一个类,与父类不同,它引入了排序关系,也就是说,请求派生类的两个元素是有意义的,哪一个更小。特别是,可以对派生类的对象数组进行排序 我的第一个方法是 class MyClass < LibraryClass def <(other) ... end def <=>(other) return 0 if self == other return -1 if self < oth
class MyClass < LibraryClass
def <(other)
...
end
def <=>(other)
return 0 if self == other
return -1 if self < other
return 1
end
# code for operators > <= >= is not shown here....
end
class MyClass
这似乎是可行的,但我认为最好改为[sic]Comparable
,因为这将免费提供大量其他方法
Comparable
的描述说我必须实现
操作符,以及其他操作符,包括==
和=代码>将自动实现。但是,我已经对父类中的=
操作符感到满意,因此不应该生成新的相等方法
=
操作符测试是否相等。如果我实现了
操作符,并且Comparable
根据
操作符实现了=
操作符,那么我将以递归调用结束对于表达式
self==other
,如何指定应调用父类的=
运算符?include使MyClass
的超类compariable
和LibraryClass
的超类compariable
。因此,在Comparable
中实现==
会覆盖在LibraryClass
中实现=
然后,您可以使用与LibraryClass
中相同的版本再次覆盖=
中的=
:
class MyClass < LibraryClass
include Comparable
def <=>(other)
# whatever
end
define_method(:==, LibraryClass.public_instance_method(:==))
end
class MyClass
首先,让我们创建一个覆盖范围的Range子类
class OddRange < Range
def ==(other)
!super
end
end
OddRange.new(1, 10) == OddRange.new(2, 7)
#=> true
其中不包括可比较的。现在,让我们创建一个子类OddRange
,并检查它的行为
class MyRange < OddRange
end
MyRange.ancestors
#=> [OddRange, Range, Enumerable, Object, Kernel, BasicObject]
MyRange.instance_method(:==).owner
#=> OddRange
rng1 = MyRange.new(1, 5)
rng2 = MyRange.new(2, 4)
rng3 = MyRange.new(1, 5)
rng1 == rng2
#=> true
rng1 == rng3
#=> false
没有意外
如果我们不希望compariable#=
覆盖MyRange#=
,我们可以执行以下操作
class MyRange
def ==(other)
method(__method__).super_method.super_method.call(other)
end
end
class MyRange
(instance_methods & OddRange.instance_methods(false)).each do |m|
define_method(m) do |other|
method(__method__).super_method.super_method.call(other)
end
end
end
rng1 = MyRange.new(1, 5)
rng2 = MyRange.new(2, 4)
rng3 = MyRange.new(1, 5)
rng1 == rng2
#=> true
rng1 == rng3
#=> false
rng1 <= rng3
#=> true
此“跳过”可比较的
并使用
的方法:=。看
现在,让我们向OddRange
添加另一个实例方法
class OddRange
def :<=(other)
(self.begin <=> self.begin) <= 0
end
end
rng1 = MyRange.new(1, 5)
rng2 = MyRange.new(2, 4)
rng1 <= rng2
#=> false
至MyRange
。更一般地说,如果我们不希望compariable
实例方法覆盖任何OddRange
实例方法(可能会随着时间的推移而改变),我们可以执行以下操作
class MyRange
def ==(other)
method(__method__).super_method.super_method.call(other)
end
end
class MyRange
(instance_methods & OddRange.instance_methods(false)).each do |m|
define_method(m) do |other|
method(__method__).super_method.super_method.call(other)
end
end
end
rng1 = MyRange.new(1, 5)
rng2 = MyRange.new(2, 4)
rng3 = MyRange.new(1, 5)
rng1 == rng2
#=> true
rng1 == rng3
#=> false
rng1 <= rng3
#=> true
类MyRange
(instance_methods&OddRange.instance_methods(false))。每个都有|
定义方法(m)do |其他|
方法(方法)。超级方法。超级方法。调用(其他)
结束
结束
结束
rng1=MyRange.new(1,5)
rng2=MyRange.new(2,4)
rng3=MyRange.new(1,5)
rng1==rng2
#=>正确
rng1==rng3
#=>错误
rng1为真
1实际上没有必要重新定义下面的
rng1
、rng2
和rng3
。你为什么拒绝Ruby方式?只需按照文档所说的去做。为什么它会以递归调用结束呢?你能澄清一下吗?@sawa:因为在我的设置中,my会调用==,这是Comparable的==,然后会再次调用my。但多亏了JörgWMittag发布的简明解决方案和CarySwoveland发布的优秀教程,我现在知道了如何正确地完成它。
def <=(other)
method(__method__).super_method.super_method.call(other)
end
class MyRange
(instance_methods & OddRange.instance_methods(false)).each do |m|
define_method(m) do |other|
method(__method__).super_method.super_method.call(other)
end
end
end
rng1 = MyRange.new(1, 5)
rng2 = MyRange.new(2, 4)
rng3 = MyRange.new(1, 5)
rng1 == rng2
#=> true
rng1 == rng3
#=> false
rng1 <= rng3
#=> true