在Ruby中重新定义平等实际上是如何工作的?

在Ruby中重新定义平等实际上是如何工作的?,ruby,equality,Ruby,Equality,作为一名新手,我仔细阅读了大量关于如何重新定义平等的指南,但没有一本真正解释它是如何工作的,只是解释了写什么 这样的代码 class Person attr_reader :name def initialize(name) @name = name end def ==(whatever) self.name == whatever.name end end 将考虑 name1 = Person.new("Jack") name1 = Person.n

作为一名新手,我仔细阅读了大量关于如何重新定义平等的指南,但没有一本真正解释它是如何工作的,只是解释了写什么

这样的代码

class Person
  attr_reader :name
  def initialize(name)
    @name = name
  end

  def ==(whatever)
    self.name == whatever.name
  end
end
将考虑

name1 = Person.new("Jack")
name1 = Person.new("Jack")

相等,而旧的
==
方法则没有,因为它比较了其他方法

然而,它实际上是如何工作的?什么是“随便”(许多人似乎写“其他”)以及它做什么?编辑:为了澄清,我理解这样做的意义,我只是不理解内部工作原理。一步一步发生了什么?whatever.name做什么?为什么?在==方法中返回真/假值如何帮助重新定义它?这些就是我在这里要问的问题

什么是“无论如何”

当你打电话时:

name1 == name2
Ruby在内部将其“转换”为函数调用:

name1.==(name2)
=
在这个函数调用中没有“特殊”的含义,它只是 函数名(就像
foo
do\u something
可能是函数名一样)

如您所见,
无论什么
都是传递给函数的参数,函数位于
=
的右侧

这称为“运算符重载”;这意味着操作员可以根据变量做不同的事情;您可以对所有运算符执行此操作,例如
(大于)、
=
(赋值)等

为什么需要self.name而不仅仅是name或@name

都是有效的,;在本例中,
name
self.name
@name
引用相同的变量。有些人只是喜欢写self.name,我就是其中之一,更明确的是,你指的是实例变量,而不是函数中的局部变量(不太“神奇”)。我也有很长的Python背景,在那里,
self
是必须的,所以我已经习惯了。
不过,在Ruby中,只写
name
似乎更为常见

而旧的==方法没有,因为它比较了其他方法

来自(我的):

在对象级别,==仅当obj和其他 是同一个对象。通常,此方法在中被重写 子类提供特定于类的含义

因此,在您的例子中,
name1
name2
显然不是同一个对象,即使它们具有相同的值。

露比不知道你认为什么是“代码>人<代码>的值,所以当你认为两个对象是相同的时,你需要改写<代码>=运算符来告诉Ruby。

< P>使用你自己的例子:

Person.new("Jack") == Person.new("Jack")
这里比较的是对象作为一个整体,它将具有不同的
object\u id
s。这将导致相等比较失败


通过覆盖
==
,您将使比较查看对您实际重要的内容,在本例中是
名称
属性。因此,在第二个
Person
对象中传递什么来计算相等性,实际上它是在查看
name
属性,而不是像覆盖
=
之前那样查看整个对象。要回答您的问题,您可以在比较中使用
name
@name
,这无关紧要
self
只是指等式左侧的对象,
无论什么
都是右侧的对象。

OP的标题询问“在Ruby中重新定义平等实际上是如何工作的?”。一般的答案是:

Ruby有几个方法可以被认为是“平等的”:
==
#equal?
#eql?
==
,所有这些方法的具体任务都与其他方法略有不同。在幕后,诸如
#==
等操作符方法的工作原理如下:

42 == 42
被翻译成

42.==( 42 )
也就是说,消息
:==,42
被发送到号码
42

42.send( :==, 42 )
在任何对象上重新定义
#==
方法时,此重新定义的方法将处理消息

虽然其他答案提到了
对象#=
的作用,但您可以注意到,对于可比较的对象(即可以添加mixin
compariable
的对象),您应该重新定义方法
#
,mixin将自行处理
#=
(以及
和code>以及一系列其他方法)

此外,OP还提出了一些次要的语法问题:什么是
什么
,以及是否需要
self.name
。这些都与等式方法无关

self.name
不是必需的,因为
self
始终是隐式接收者。可以只编写
name==which.name
,而不是
self.name==which.name
。过度使用显式的
self
可以被认为是一种pythonism
@name
不能使用,因为它表示其他内容(引用实例变量)

在方法定义中

def ==( whatever )
  name == whatever.name
end
无论什么
都是一个参数。正在使用单个参数
定义该方法。因此,当调用该方法时,它将需要一个参数,并将该参数指定给局部变量
which
。这只是方法定义语法,没有其他内容


总而言之,OP询问的
#=
版本将
Person
类的对象按名称进行比较,如果它们的名称相等,即使它们不是相同的对象,也会认为它们相等。

请参见下面我的答案:

  • 然而,它实际上是如何工作的
  • 编写name1==name2时,实际上是将name2变量发送到实例方法 ==(无论什么)

  • 什么是“随便”(许多人似乎写“其他”)以及它做什么
  • 是na吗
    name1 = Person.new("Jack")
    
    name2 = Person.new("Jack")
    
    name1 == name2
    
    name1.==(name2)
    
    def foo(bar)
      puts bar
    end
    
    a = 'b'
    
    foo(a) #=> "b"