对象与fixnum的比较

时间:2014-07-11 16:27:17

标签: ruby

我希望能够将对象与fixnums进行比较。

class Dog
  include Comparable
  def <=>(other)
    1
  end
end

鉴于上述课程,为什么会这样做:

dog = Dog.new
array = [2, 1, 4, dog]
array.min
=> 1

但这不是:

dog = Dog.new
array = [dog, 2, 1, 4]
array.min
ArgumentError: comparison of Fixnum with Dog failed
    from (irb):11:in `each'
    from (irb):11:in `min'
    from (irb):11

当对象是第一个元素时,为什么我不能将对象与数字进行比较? 有什么办法可以解决这个问题吗?我希望Dog对象在与数组中的任何其他值进行比较时始终是最大的值,这就是我在&lt; =&gt;中将其设置为1的原因。方法

谢谢!

3 个答案:

答案 0 :(得分:4)

要与数字类型进行比较,您可以实施coerce

class Dog
  include Comparable

  def initialize(age)
    @age = age
  end

  def <=>(other)
    @age <=> other
  end

  def coerce(numeric)
    [numeric, @age]
  end
end

Dog.new(5) <=> Dog.new(5)  #=>  0
Dog.new(5) <=> 1           #=>  1
         1 <=> Dog.new(5)  #=> -1

[1, 3, Dog.new(2)].sort
#=> 1, #<Dog @age=2>, 3]

无需使用sort_by实施<=>coerce即可实现上述排序:

class Dog
  attr_accessor :age

  def initialize(age)
    @age = age
  end
end

[1, 3, Dog.new(2)].sort_by { |obj| obj.is_a?(Dog) ? obj.age : obj }
#=> 1, #<Dog @age=2>, 3]

还有min_bymax_by

答案 1 :(得分:3)

为了允许DogFixnum进行比较,您还需要在Fixnum上实施比较:

class Fixnum
  alias :my_compare :'<=>'
  def <=>(other)
    if other.is_a? Dog
      return -1
    end
    my_compare(other)
  end
end

array.min
# => 1

array.max
# => #<Dog:0x8f712fc>

答案 2 :(得分:0)

这是因为<=>在数学意义上不是二元关系(即,在 A ^ 2上为某些集合 A 定义),但是对象的方法,不对称。允许other中的Foo#<=>(other)成为Bar的实例并不意味着other中的Bar#<=>(other)可以是Foo