我希望能够将对象与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的原因。方法
谢谢!
答案 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]
答案 1 :(得分:3)
为了允许Dog
与Fixnum
进行比较,您还需要在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
。