关于ruby:equal?,eql?,===和==之间有什么区别?

What's the difference between equal?, eql?, ===, and ==?

我试图理解这四种方法之间的区别。我知道默认情况下,==调用方法equal?,当两个操作数引用完全相同的对象时,该方法返回true。

默认情况下,===也调用==,后者调用equal?…好吧,如果这三个方法都没有被重写,那么我想=====equal?做的完全一样?

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

为什么Ruby有这么多平等的标志?他们应该在语义上有所不同吗?


我将在这里大量引用对象文档,因为我认为它有一些很好的解释。我鼓励您阅读它,以及这些方法的文档,因为它们在其他类(如字符串)中被重写。

旁注:如果您想在不同的对象上自己尝试这些方法,请使用如下方法:

1
2
3
4
5
6
7
8
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}

==—一般"等同性"

At the Object level, == returns true only if obj and other are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.

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

===—大小写相等

For class Object, effectively the same as calling #==, but typically overridden by descendants to provide meaningful semantics in case statements.

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

  • 范围
  • 正则表达式
  • proc(在ruby 1.9中)

所以你可以这样做:

1
2
3
4
5
6
7
8
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

请看我的答案,以获得一个很好的例子,说明caseRegex如何使代码更干净。当然,通过提供您自己的===实现,您可以获得定制的case语义。

eql?Hash相等

The eql? method returns true if obj and other refer to the same hash key. This is used by Hash to test members for equality. For objects of class Object, eql? is synonymous with ==. Subclasses normally continue this tradition by aliasing eql? to their overridden == method, but there are exceptions. Numeric types, for example, perform type conversion across ==, but not across eql?, so:

1
2
1 == 1.0     #=> true
1.eql? 1.0   #=> false

所以您可以自由地为自己的使用而重写它,或者您可以重写==并使用alias :eql? :==,这样这两个方法的行为相同。

equal?—身份比较

Unlike ==, the equal? method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b) iff a is the same object as b).

这实际上是指针比较。


我喜欢JTBandes答案,但由于它很长,我将添加我自己的简洁答案:

=====eql?equal?。是4个比较器,即用Ruby比较2个对象的4种方法。在Ruby中,所有的比较器(和大多数运算符)实际上都是方法调用,您可以自己更改、覆盖和定义这些比较方法的语义。但是,当Ruby的内部语言构造使用哪个比较器时,理解这一点很重要:

==(价值比较)Ruby使用:==Everywhere来比较2个对象的值,例如哈希值:

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

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

1
2
3
4
5
6
7
case foo
  when bar;  p 'do something'
end

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

eql?(哈希键比较)Ruby使用:eql?(与方法hash结合)比较hash键。在大多数课程中:eql?与:==相同。了解:eql?只有当您想创建自己的特殊类时,才重要:

1
2
3
4
5
6
7
8
9
10
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类集还依赖于哈希键比较。

equal?(对象身份比较)红宝石用途:相等?检查两个对象是否相同。这个方法(属于basicObject类)不应该被覆盖。

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


相等运算符:==和!=

==运算符,也称为equality或double equal,如果两个对象相等,则返回true;否则返回false。好的。

1
"koan" =="koan" # Output: => true

这个!=运算符,也称为不等式,与==相反。如果两个对象不相等,则返回"真";如果两个对象相等,则返回"假"。好的。

1
"koan" !="discursive thought" # Output: => true

请注意,两个元素顺序不同的数组是不相等的,同一字母的大小写版本是不相等的,依此类推。好的。

当比较不同类型的数字(例如整数和浮点)时,如果它们的数值相同,==将返回真。好的。

1
2 == 2.0 # Output: => true

相等?

与测试两个操作数是否相等的==运算符不同,equal方法检查两个操作数是否引用同一对象。这是Ruby中最严格的平等形式。好的。

例子:"禅""禅"好的。

1
2
3
4
a.object_id  # Output: => 20139460
b.object_id  # Output :=> 19972120

a.equal? b  # Output: => false

在上面的示例中,我们有两个值相同的字符串。但是,它们是两个不同的对象,具有不同的对象ID。因此,平等?方法将返回false。好的。

让我们再试一次,只是这次b将是对a的引用。请注意,两个变量的对象ID是相同的,因为它们指向同一个对象。好的。

1
2
3
4
5
6
7
a ="zen"
b = a

a.object_id  # Output: => 18637360
b.object_id  # Output: => 18637360

a.equal? b  # Output: => true

EQL?

在hash类中,eql?方法用于测试键是否相等。需要一些背景来解释这一点。在计算的一般上下文中,哈希函数接受任意大小的字符串(或文件),并生成一个固定大小的字符串或整数,称为hashcode,通常称为only hash。一些常用的哈希代码类型是MD5、SHA-1和CRC。它们用于加密算法、数据库索引、文件完整性检查等。一些编程语言(如Ruby)提供一种称为哈希表的集合类型。哈希表是类似字典的集合,成对存储数据,由唯一键及其对应值组成。在发动机罩下,这些钥匙存储为哈希代码。哈希表通常只被称为哈希表。注意单词hashcan如何引用哈希代码或哈希表。在Ruby编程的上下文中,单词hash几乎总是指类似字典的集合。好的。

Ruby提供了一个名为hash的内置方法来生成哈希代码。在下面的示例中,它接受一个字符串并返回一个哈希代码。请注意,具有相同值的字符串总是具有相同的哈希代码,即使它们是不同的对象(具有不同的对象ID)。好的。

1
2
3
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547

哈希方法在内核模块中实现,包含在对象类中,对象类是所有Ruby对象的默认根。一些类(如symbol和integer)使用默认实现,其他类(如string和hash)提供自己的实现。好的。

1
2
3
4
5
Symbol.instance_method(:hash).owner  # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel

String.instance_method(:hash).owner  # Output: => String
Hash.instance_method(:hash).owner  # Output: => Hash

当我们在Ruby中,商店的东西在hash(collection),AS(the Key对象提供,如字符串或符号)和存储转换into is as a的hash码。当查询后,安元(collection)from the hash对象,我们提供安as a key,which is into a转换compared to the existing hashCode和钥匙。if there is the value of the match,对应item is returned。is using the EQL比较自制的茶?在罩的方法。>

1
2
3
"zen".eql?"zen"    # Output: => true
# is the same as
"zen".hash =="zen".hash # Output: => true

在the most cases,EQL?behaves similarly method to the method = =。不管一个人多了一些,there are。for instance,EQL?does not做隐式转换时,an integer型浮法to a?比较。>

1
2
3
2 == 2.0    # Output: => true
2.eql? 2.0    # Output: => false
2.hash == 2.0.hash  # Output: => false

家庭平等社:===

在S -红宝石many of such as新建类,字符串,布尔表达式,范围,提供他们自己的implementations = of the known as operator,房子也threequals平等,等于前三。因为它要实现在每一页differently舱,将常用differently depending on the type of object was called恩先生generally归来true if the object,它由"belongs to the right"或"is of the对象成员的"on the left。for instance,it can be used to an object is an instance测试if(or of a class one of its subclasses)。>

1
2
3
4
String ==="zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

result can be the same with other which are probably方法实现最佳suited for the job。这是更好的usually that is to write队列读易"as as possible显式模式,在效率和conciseness sacrificing。>

1
2
3
2.is_a? Integer   # Output: => true
2.kind_of? Integer  # Output: => true
2.instance_of? Integer # Output: => false

通知我integers returned the last example such as 2是错误的情况下,fixnum of the class,which is a class of the subclass integer。===_ is the,a?_和instance of?方法返回true if the object is an instance of the class or any given subclasses。_ method is the instance of the true if and only stricter归来is an instance of that精确对象类,subclass not a。>

_ the is?和_ kind of?要实现的方法是在核心模块中,which is the class对象的混合模式。别名to the same method are both。我们的验证:>

kernel.instance _ method(:_ kind of?)kernel.instance(:= _ method is _?)#输出:=>True>

范围= implementation of

when the = is called on a范围内经营者的对象,它返回true if the value on the right on the left the范围内的瀑布。>

1
2
3
4
5
6
(1..4) === 3  # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6  # Output: => false

("a".."d") ==="c" # Output: => true
("a".."d") ==="e" # Output: => false

记住that the======invokes社the method of the left手对象。我(1 = 4)3(1到4)是等价的。===3。在其他的话,the class of the left手操作数执行of the which will define method = will be called the are not,interchangeable知道操作数的位置。>

regexp implementation of===

返回true if the字符串正则表达式on the right on the left the matches。//=="禅打坐实践=>:今日"#输出true# is the same as"实践禅打坐今日"= ~ / />

在case/when语句上隐式使用===运算符

此运算符也用于"打开案例/时间"语句的软篷下。这是它最常用的用法。好的。

1
2
3
4
5
6
7
8
9
10
minutes = 15

case minutes
  when 10..20
    puts"match"
  else
    puts"no match"
end

# Output: match

在上面的示例中,如果Ruby隐式使用了double equal运算符(==),那么范围10..20将不被视为等于整数,如15。它们匹配是因为在所有case/when语句中都隐式使用了三重相等运算符(==)。上面示例中的代码等价于:好的。

1
2
3
4
5
if (10..20) === minutes
  puts"match"
else
  puts"no match"
end

模式匹配运算符:=~和!~

=~(等号)和!~(bang tilde)运算符用于根据regex模式匹配字符串和符号。好的。

字符串和符号类中的=~方法的实现需要正则表达式(regexp类的实例)作为参数。好的。

1
2
3
4
5
"practice zazen" =~ /zen/   # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil

:zazen =~ /zen/    # Output: => 2
:zazen =~ /discursive thought/  # Output: => nil

regexp类中的实现需要一个字符串或符号作为参数。好的。

1
2
/zen/ =~"practice zazen"  # Output: => 11
/zen/ =~"discursive thought" # Output: => nil

在所有实现中,当字符串或符号与regexp模式匹配时,它返回一个整数,即匹配的位置(索引)。如果没有匹配项,则返回零。记住,在Ruby中,任何整数值都是"truthy",nil是"falsy",因此=~运算符可以用于if语句和三元运算符。好的。

1
2
puts"yes" if"zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes

模式匹配运算符对于编写较短的if语句也很有用。例子:好的。

1
2
3
4
5
6
7
if meditation_type =="zazen" || meditation_type =="shikantaza" || meditation_type =="kinhin"
  true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
  true
end

这个!~ operator与=~相反,如果没有匹配,则返回true;如果有匹配,则返回false。好的。

有关详细信息,请访问此日志。好的。好啊。


我想扩大对===的操作。

===不是一个相等运算符!

不是。

让我们把这一点讲清楚。

在javascript和php中,您可能熟悉===作为一个相等运算符,但这在Ruby中并不是一个相等运算符,并且具有根本不同的语义。

那么,===是做什么的?

===是模式匹配操作符!

  • ===匹配正则表达式
  • ===检查范围成员
  • ===检查是一个类的实例
  • ===调用lambda表达式
  • ===有时检查平等性,但大多数情况下不检查平等性。

那么这种疯狂有什么意义呢?

  • Enumerable#grep内部使用===
  • case when报表内部使用===
  • 有趣的是,rescue在内部使用===

这就是为什么可以在case when语句中使用正则表达式、类和范围,甚至lambda表达式的原因。

一些实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
case value
when /regexp/
  # value matches this regexp
when 4..10
  # value is in range
when MyClass
  # value is an instance of class
when ->(value) { ... }
  # lambda expression returns true
when a, b, c, d
  # value matches one of a through d with `===`
when *array
  # value matches an element in array with `===`
when x
  # values is equal to x unless x is one of the above
end

所有这些示例也适用于pattern === value,以及grep方法。

1
2
3
4
5
6
7
8
9
arr = ['the', 'quick', 'brown', 'fox', 1, 1, 2, 3, 5, 8, 13]
arr.grep(/[qx]/)                                                                                                                            
# => ["quick","fox"]
arr.grep(4..10)
# => [5, 8]
arr.grep(String)
# => ["the","quick","brown","fox"]
arr.grep(1)
# => [1, 1]

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

1
2
3
4
5
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

希望它能帮助别人。


==---大小写相等==---一般相等

两者工作原理相似,但"=="偶数do case语句

1
2
"test" =="test"  #=> true
"test" ==="test" #=> true

这里的区别

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


我为以上所有内容编写了一个简单的测试。

1
2
3
4
5
6
7
8
9
10
11
12
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)