我有一个库类,它提供了相等和不等的方法。我从这里派生出另一个类,与父类不同,它引入了一个排序关系,即要求派生类的两个元素是有意义的,哪一个更小。特别是,可以对派生类的对象数组进行排序。
我的第一个方法是
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
这似乎有效,但我认为改为[原文如此] Comparable
可能会更好,因为这样可以免费提供大量其他方法。
Comparable
的说明我必须实施<=>
运算符,然后会自动实施包括==
和!=
在内的其他运算符。但是,我对父类的==
运算符感到满意,因此不应生成相等的新方法。
我想使用父类中的==
运算符测试是否相等。如果我实施<=>
运算符,并且Comparable
根据我的==
运算符实现了<=>
运算符,那么我最终会进行递归调用。
对于表达式self == other
,如何指定应调用父类的==
运算符?
答案 0 :(得分:2)
include
使Comparable
的超类MyClass
和LibraryClass
的超类成为Comparable
的超类。因此,==
中Comparable
的实施会覆盖==
中LibraryClass
的实施。
您可以做的是,使用与==
中的版本相同的版本覆盖MyClass
中的LibraryClass
:
class MyClass < LibraryClass
include Comparable
def <=>(other)
# whatever
end
define_method(:==, LibraryClass.public_instance_method(:==))
end
答案 1 :(得分:1)
首先,让我们创建一个覆盖Range#==
的Range子类。
class OddRange < Range
def ==(other)
!super
end
end
OddRange.new(1, 10) == OddRange.new(2, 7)
#=> true
请注意
OddRange.included_modules
#=> [Enumerable, Kernel]
不包括Comparable
。现在让我们创建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
我们接下来include
将模块Comparable
导入MyRange
,然后将实例方法添加到MyRange
1 。
class MyRange
def <=>(other)
self.end <=> other.end
end
include Comparable
end
MyRange.ancestors
#=> [MyRange, MyComparable, OddRange, Range, Enumerable, Object, Kernel, BasicObject]
MyRange.instance_method(:==).owner
#=> Comparable
rng1 = MyRange.new(1, 5)
rng2 = MyRange.new(2, 4)
rng3 = MyRange.new(1, 5)
rng1 == rng2
#=> false
rng1 == rng3
#=> true
rng1 <=> rng2
#=> 1
没有惊喜。
如果我们不希望Comparable#==
覆盖MyRange#==
,我们可以执行以下操作。
class MyRange
def ==(other)
method(__method__).super_method.super_method.call(other)
end
end
这&#34;跳过&#34; Comparable
并使用OddRange
方法:==
。请参阅Method#super_method。
rng1 = MyRange.new(1, 5)
rng2 = MyRange.new(2, 4)
rng3 = MyRange.new(1, 5)
rng1 == rng2
#=> true
rng1 == rng3
#=> false
现在让我们为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
我们看到Comparable#<=
和MyRange#<>
导致rng1 <= rng2
返回false
。如果我们希望改为使用OddRange#<=
,我们当然可以做我们以前做过的事情,添加
def <=(other)
method(__method__).super_method.super_method.call(other)
end
到MyRange
。更一般地说,如果我们不希望Comparable
实例方法覆盖任何 OddRange
实例方法(可能随时间而变化),我们可以执行以下操作。< / p>
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
1实际上不需要重新定义rng1
,rng2
和rng3
。