覆盖 == 相等运算符仅在一个方向上起作用

Overriding == equality operator works only in one direction

提问人:illusionist 提问时间:8/23/2017 最后编辑:Danil Speranskyillusionist 更新时间:8/23/2017 访问量:171

问:

考虑下一个示例,其中我覆盖运算符以不断返回:==true

class Example
  def ==(other)
    return true
  end
end

但是,这仅在一个方向上起作用:

exp = Example.new
puts exp == {} #=> true
puts {} == exp #=> false

有没有办法迫使这种相等方法在相反的方向上工作?

Ruby OOP 运算符重载重 相等性

评论


答:

1赞 Danil Speransky 8/23/2017 #1

如果不更改其他类,这是不可能的。基本上等于.因此,如果你想让它工作,你需要覆盖第二个类的运算符。a == ba.==(b)==

1赞 Sergio Tulentsev 8/23/2017 #2

有没有办法迫使这种相等方法也向相反的方向工作?

不可以,但您可以更改以识别 的特殊情况。Hash#==Example

class Example
  def ==(other)
    return true
  end
end

class Hash
  alias_method :original_double_equals, :==

  def ==(other)
    case other
    when Example
      other == self
    else
      original_double_equals(other)
    end
  end
end


exp = Example.new
exp == {} # => true
{} == exp # => true
{} == {} # => true
{foo: 1} == {foo: 2} # => false

如果我是你,我不会这样做。

评论

1赞 Simple Lime 8/23/2017
您也可以在重新定义方法之前为该方法添加别名:在示例中的第 7 行和第 8 行之间,然后调用 ...产生 、 、 作为输出==alias :original_double_equals :"=="superoriginal_double_equals(other)truetruetruefalse
0赞 Sergio Tulentsev 8/23/2017
@SimpleLime:实际上,这听起来确实是一个更好的主意。Lemme 这样做
1赞 Jörg W Mittag 8/23/2017 #3

不,这是不可能的。

Ruby 是一种面向对象的语言。OO 的基本思想是向对象和接收对象发送消息,只有接收对象才能决定如何响应该消息。

  • 如果将消息发送到 object ,将 object 作为参数传递,则 and a 可以单独决定如何响应。==aba
  • 如果将消息发送到 object ,将 object 作为参数传递,则 b 可以单独决定如何响应。==bab

保证给出相同响应的唯一方法是,如果 and 合作并同意给出相同的响应。ab

从理论上讲,可以设计一种语言,即不是将消息发送到 或 ,而是将消息发送到第三个“上下文对象”。IOW,不被解释为 or 而是 (例如,上下文对象可能只是你自己,即 )。在这种情况下,上下文对象可以访问两者的公共 API,并且可以采取措施确保它是可交换的。a == baba == ba.==(b)b.==(a)some_context_object.==(a, b)self.==(a, b)ab==

但总的来说,由于OO的基本性质,消息是不可交换的,接收对象是特殊的。