我试图理解这四种方法之间的区别。我知道默认情况下==调用方法等于?当两个操作数都指向同一个对象时返回true。

===默认也调用==哪个调用equal?…如果这三个方法都没有被覆盖,那么我猜 ===, == and equal?做完全一样的事情?

现在是eql?。这是做什么(默认情况下)?它是否调用操作数的哈希/id?

为什么Ruby有这么多等号?它们应该在语义上有所不同吗?


当前回答

.eql吗?—如果接收方和实参具有相同类型且值相等,则此操作符返回true。

例如- 10.eql?(10.0)为假值。

=== -它将在case语句中测试是否相等。

例如-(1…10)=== 1为真

== -该操作符检查两个给定的操作数是否相等。如果等于,则返回TRUE,否则返回FALSE。

例如-(1…10)== 1为假

更多示例请点击这里

其他回答

我将在这里大量引用Object文档,因为我认为它有一些很好的解释。我鼓励你阅读它,还有这些方法的文档,因为它们在其他类中被重写了,比如String。

旁注:如果你想自己在不同的对象上尝试这些,可以使用这样的东西:

class Object
  def all_equals(o)
    ops = [:==, :===, :eql?, :equal?]
    Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
  end
end

"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}

== -一般的"平等"

在Object级别,==仅当obj和other是同一个对象时才返回true。通常,这个方法在子类中被重写,以提供特定于类的含义。

这是最常见的比较,因此也是您(作为类的作者)决定两个对象是否“相等”的最基本的地方。

=== - case相等

对于Object类,实际上与调用#==相同,但通常由后代重写,以在case语句中提供有意义的语义。

这是非常有用的。有趣的===实现的例子:

范围 正则表达式 Proc(在Ruby 1.9中)

所以你可以这样做:

case some_object
when /a regex/
  # The regex matches
when 2..4
  # some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
  # the lambda returned true
end

这里有一个简洁的例子,说明case+Regex如何使代码更简洁。当然,通过提供您自己的===实现,您可以获得自定义大小写语义。

eql吗?-哈希等价

eql吗?如果obj和other指向相同的散列键,则方法返回true。Hash使用它来测试成员是否相等。对于Object类的对象,eql?是==的同义词。子类通常通过别名eql?它们被重写的==方法,但也有例外。例如,数值类型跨==执行类型转换,但不跨eql?,所以: 1 == 1.0 #=> true 1. eql ?1.0 #=> false

因此,您可以自由地为自己的用途覆盖它,或者您可以覆盖==并使用别名:eql?:==所以这两个方法的行为是相同的。

等于多少?-身份比较

不像==,相等?方法永远不应该被子类覆盖:它用于确定对象的身份(即a.equal?(b)如果a与b是相同的对象)。

这是有效的指针比较。

我喜欢jtband的答案,但因为它太长了,我将添加我自己的紧凑答案:

==, ===, eql?,等于多少? 是四个比较器,即。Ruby中比较两个对象的4种方法。 在Ruby中,所有比较器(和大多数操作符)实际上都是方法调用,因此您可以自己更改、覆盖和定义这些比较方法的语义。然而,重要的是要理解,当Ruby的内部语言构造使用哪个比较器:

==(价值比较) Ruby在任何地方都使用:==来比较两个对象的值,例如。散列值:

{a: 'z'}  ==  {a: 'Z'}    # => false
{a: 1}    ==  {a: 1.0}    # => true

===(案例比较) Ruby在case/when结构中使用:===。下面的代码段在逻辑上是相同的:

case foo
  when bar;  p 'do something'
end

if bar === foo
  p 'do something'
end

eql吗?(散列值的比较) Ruby使用:eql?(结合哈希方法)来比较哈希键。在大多数类中:eql?与:==相同。 关于:eql?只有当你想创建自己的特殊类时才重要:

class Equ
  attr_accessor :val
  alias_method  :initialize, :val=
  def hash()           self.val % 2             end
  def eql?(other)      self.hash == other.hash  end
end

h = {Equ.new(3) => 3,  Equ.new(8) => 8,  Equ.new(15) => 15}    #3 entries, but 2 are :eql?
h.size            # => 2
h[Equ.new(27)]    # => 15

注意:常用的ruby类集也依赖于哈希键比较。

等于多少?(对象身份比较) Ruby使用:equal?来检查两个对象是否相同。(BasicObject类的)这个方法不应该被覆盖。

obj = obj2 = 'a'
obj.equal? obj2       # => true
obj.equal? obj.dup    # => false

=== #——大小写相等

== #——一般相等

两者的工作原理类似,但“===”甚至可以执行case语句

"test" == "test"  #=> true
"test" === "test" #=> true

区别就在这里

String === "test"   #=> true
String == "test"  #=> false

我编写了一个简单的测试。

def eq(a, b)
  puts "#{[a, '==',  b]} : #{a == b}"
  puts "#{[a, '===', b]} : #{a === b}"
  puts "#{[a, '.eql?', b]} : #{a.eql?(b)}"
  puts "#{[a, '.equal?', b]} : #{a.equal?(b)}"
end

eq("all", "all")
eq(:all, :all)
eq(Object.new, Object.new)
eq(3, 3)
eq(1, 1.0)

Ruby公开了处理相等的几种不同方法:

a.equal?(b) # object identity - a and b refer to the same object

a.eql?(b) # object equivalence - a and b have the same value

a == b # object equivalence - a and b have the same value with type conversion.

点击下面的链接继续阅读,它给了我一个清晰的总结理解。

https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers

希望它能帮助别人。