如果父类已经有'=='

时间:2017-06-12 10:22:53

标签: ruby

我有一个库类,它提供了相等和不等的方法。我从这里派生出另一个类,与父类不同,它引入了一个排序关系,即要求派生类的两个元素是有意义的,哪一个更小。特别是,可以对派生类的对象数组进行排序。

我的第一个方法是

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可能会更好,因为这样可以免费提供大量其他方法。

  1. Comparable的说明我必须实施<=>运算符,然后会自动实施包括==!=在内的其他运算符。但是,我对父类的==运算符感到满意,因此不应生成相等的新方法。

  2. 我想使用父类中的==运算符测试是否相等。如果我实施<=>运算符,并且Comparable根据我的==运算符实现了<=>运算符,那么我最终会进行递归调用。

    < / LI>

    对于表达式self == other,如何指定应调用父类的==运算符?

2 个答案:

答案 0 :(得分:2)

include使Comparable的超类MyClassLibraryClass的超类成为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实际上不需要重新定义rng1rng2rng3