天天看点

equal?,eql?,===和==之间有什么区别? === #---case equality ===#---大小写相等 == #--- generic equality ==#---泛型相等

本文翻译自:What's the difference between equal?, eql?, ===, and ==?

I am trying to understand the difference between these four methods.

我试图了解这四种方法之间的区别。

I know by default that

==

calls the method

equal?

我知道默认情况下

==

调用方法是否

equal?

which returns true when both operands refer to exactly the same object.

当两个操作数都引用完全相同的对象时,它返回true。

===

by default also calls

==

which calls

equal?

默认情况下

===

也调用

==

哪个调用

equal?

... okay, so if all these three methods are not overridden, then I guess

===

,

==

and

equal?

...好吧,如果这三个方法都没有被覆盖,那么我猜

===

==

equal?

do exactly the same thing?

做完全一样的事情?

Now comes

eql?

现在是

eql?

.

What does this do (by default)?

这是做什么的(默认情况下)?

Does it make a call to the operand's hash/id?

它是否调用操作数的哈希/ ID?

Why does Ruby have so many equality signs?

为什么Ruby有这么多相等标志?

Are they supposed to differ in semantics?

他们应该在语义上有所不同吗?

#1楼

参考:https://stackoom.com/question/U1ql/equal-eql-和-之间有什么区别

#2楼

=== #---case equality ===#---大小写相等

== #--- generic equality ==#---泛型相等

both works similar but "===" even do case statements

两者的工作原理相似,但“ ===”甚至可以做案例陈述
"test" == "test"  #=> true
"test" === "test" #=> true
           

here the difference

这里的区别
String === "test"   #=> true
String == "test"  #=> false
           

#3楼

I wrote a simple test for all the above.

我为上述所有内容编写了一个简单的测试。
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)
           

#4楼

I love jtbandes answer, but since it is pretty long, I will add my own compact answer:

我喜欢jtbandes答案,但是由于它很长,因此我将添加自己的紧凑型答案:

==

,

===

,

eql?

==

===

eql?

,

equal?

equal?

are 4 comparators, ie.

是4个比较器,即

4 ways to compare 2 objects, in Ruby.

在Ruby中比较2个对象的4种方法。

As, in Ruby, all comparators (and most operators) are actually method-calls, you can change, overwrite, and define the semantics of these comparing methods yourself.

因为在Ruby中,所有比较器(和大多数运算符)实际上都是方法调用,所以您可以自己更改,覆盖和定义这些比较方法的语义。

However, it is important to understand, when Ruby's internal language constructs use which comparator:

但是,重要的是要理解,当Ruby的内部语言构造使用哪个比较器时:

==

(value comparison)

==

(值比较)

Ruby uses :== everywhere to compare the values of 2 objects, eg.

Ruby在所有地方都使用:==来比较2个对象的值 ,例如。

Hash-values:

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

===

(case comparison)

===

(案例比较)

Ruby uses :=== in case/when constructs.

在构造时,Ruby使用:===。

The following code snippets are logically identical:

以下代码段在逻辑上是相同的:
case foo
  when bar;  p 'do something'
end

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

eql?

(Hash-key comparison)

(哈希键比较)

Ruby uses :eql?

Ruby使用:eql?

(in combination with the method hash) to compare Hash-keys.

(与方法hash结合使用)以比较Hash键。

In most classes :eql?

在大多数课程中:eql?

is identical with :==.

与:==相同。

Knowledge about :eql?

有关:eql的知识?

is only important, when you want to create your own special classes:

仅在要创建自己的特殊类时才重要:
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
           

Note: The commonly used Ruby-class Set also relies on Hash-key-comparison.

注意:常用的Ruby-Class Set也依赖于Hash-key-comparison。

equal?

(object identity comparison)

(对象身份比较)

Ruby uses :equal?

Ruby使用:equal?

to check if two objects are identical.

检查两个对象是否相同。

This method (of class BasicObject) is not supposed to be overwritten.

(属于BasicObject类的)此方法不应被覆盖。
obj = obj2 = 'a'
obj.equal? obj2       # => true
obj.equal? obj.dup    # => false
           

#5楼

Ruby exposes several different methods for handling equality:

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.
                

Continue reading by clicking the link below, it gave me a clear summarized understanding.

单击下面的链接继续阅读,它给了我清晰的摘要理解。
https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers

Hope it helps others.

希望它能帮助别人。

#6楼

Equality operators: == and != 等号运算符:==和!=

The == operator, also known as equality or double equal, will return true if both objects are equal and false if they are not.

==运算符,也称为相等或双精度相等,如果两个对象相等,则返回true,否则返回false。
"koan" == "koan" # Output: => true
           

The != operator, also known as inequality, is the opposite of ==.

!=运算符(也称为不等式)与==相反。

It will return true if both objects are not equal and false if they are equal.

如果两个对象不相等,则返回true;如果相等,则返回false。
"koan" != "discursive thought" # Output: => true
           

Note that two arrays with the same elements in a different order are not equal, uppercase and lowercase versions of the same letter are not equal and so on.

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

When comparing numbers of different types (eg, integer and float), if their numeric value is the same, == will return true.

比较不同类型的数字(例如整数和浮点数)时,如果它们的数值相同,则==将返回true。
2 == 2.0 # Output: => true
           

equal? 等于?

Unlike the == operator which tests if both operands are equal, the equal method checks if the two operands refer to the same object.

与==运算符测试两个操作数是否相等不同,equal方法检查两个操作数是否引用相同的对象。

This is the strictest form of equality in Ruby.

这是Ruby中最严格的相等形式。

Example: a = "zen" b = "zen"

例如:a =“ zen” b =“ zen”
a.object_id  # Output: => 20139460
b.object_id  # Output :=> 19972120

a.equal? b  # Output: => false
           

In the example above, we have two strings with the same value.

在上面的示例中,我们有两个具有相同值的字符串。

However, they are two distinct objects, with different object IDs.

但是,它们是两个不同的对象,具有不同的对象ID。

Hence, the equal?

因此,等于?

method will return false.

方法将返回false。

Let's try again, only this time b will be a reference to a.

让我们再试一次,仅这次b是对a的引用。

Notice that the object ID is the same for both variables, as they point to the same object.

注意,两个变量的对象ID相同,因为它们指向同一对象。
a = "zen"
b = a

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

a.equal? b  # Output: => true
           

eql? eql?

In the Hash class, the eql?

在Hash类中,eql?

method it is used to test keys for equality.

用于测试密钥是否相等的方法。

Some background is required to explain this.

需要一些背景来解释这一点。

In the general context of computing, a hash function takes a string (or a file) of any size and generates a string or integer of fixed size called hashcode, commonly referred to as only hash.

在计算的一般上下文中,哈希函数采用任意大小的字符串(或文件),并生成称为哈希码(通常仅称为哈希)的固定大小的字符串或整数。

Some commonly used hashcode types are MD5, SHA-1, and CRC.

一些常用的哈希码类型是MD5,SHA-1和CRC。

They are used in encryption algorithms, database indexing, file integrity checking, etc. Some programming languages, such as Ruby, provide a collection type called hash table.

它们用于加密算法,数据库索引,文件完整性检查等。某些编程语言(例如Ruby)提供一种称为哈希表的集合类型。

Hash tables are dictionary-like collections which store data in pairs, consisting of unique keys and their corresponding values.

哈希表是类似于字典的集合,它们成对存储数据,由唯一键及其对应的值组成。

Under the hood, those keys are stored as hashcodes.

在后台,这些密钥存储为哈希码。

Hash tables are commonly referred to as just hashes.

哈希表通常称为哈希表。

Notice how the word hashcan refer to a hashcode or to a hash table.

请注意,hash一词如何引用哈希码或哈希表。

In the context of Ruby programming, the word hash almost always refers to the dictionary-like collection.

在Ruby编程的上下文中,哈希一词几乎总是指类似于字典的集合。

Ruby provides a built-in method called hash for generating hashcodes.

Ruby提供了一种称为hash的内置方法,用于生成哈希码。

In the example below, it takes a string and returns a hashcode.

在下面的示例中,它接受一个字符串并返回一个哈希码。

Notice how strings with the same value always have the same hashcode, even though they are distinct objects (with different object IDs).

注意具有相同值的字符串如何始终具有相同的哈希码,即使它们是不同的对象(具有不同的对象ID)也是如此。
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547
           

The hash method is implemented in the Kernel module, included in the Object class, which is the default root of all Ruby objects.

hash方法在Object类中包含的Kernel模块中实现,该模块是所有Ruby对象的默认根目录。

Some classes such as Symbol and Integer use the default implementation, others like String and Hash provide their own implementations.

一些类(例如Symbol和Integer)使用默认实现,而其他类(例如String和Hash)提供其自己的实现。
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
           

In Ruby, when we store something in a hash (collection), the object provided as a key (eg, string or symbol) is converted into and stored as a hashcode.

在Ruby中,当我们将某些内容存储在哈希(集合)中时,将作为键提供的对象(例如字符串或符号)转换为哈希码并存储为哈希码。

Later, when retrieving an element from the hash (collection), we provide an object as a key, which is converted into a hashcode and compared to the existing keys.

稍后,当从哈希(集合)中检索元素时,我们提供一个对象作为键,该对象被转换为哈希码并与现有键进行比较。

If there is a match, the value of the corresponding item is returned.

如果存在匹配项,则返回相应项目的值。

The comparison is made using the eql?

使用eql进行比较。

method under the hood.

引擎盖下的方法。
"zen".eql? "zen"    # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true
           

In most cases, the eql?

在大多数情况下,eql?

method behaves similarly to the == method.

方法的行为类似于==方法。

However, there are a few exceptions.

但是,也有一些例外。

For instance, eql?

例如,eql?

does not perform implicit type conversion when comparing an integer to a float.

比较整数和浮点数时,不执行隐式类型转换。
2 == 2.0    # Output: => true
2.eql? 2.0    # Output: => false
2.hash == 2.0.hash  # Output: => false
           

Case equality operator: === 大小写相等运算符:===

Many of Ruby's built-in classes, such as String, Range, and Regexp, provide their own implementations of the === operator, also known as case-equality, triple equals or threequals.

Ruby的许多内置类,例如String,Range和Regexp,提供了自己===运算符的实现,也称为大小写相等,三等号或三等值。

Because it's implemented differently in each class, it will behave differently depending on the type of object it was called on.

由于在每个类中实现的方式不同,因此根据调用对象的类型,其行为也将有所不同。

Generally, it returns true if the object on the right "belongs to" or "is a member of" the object on the left.

通常,如果右侧的对象“属于”左侧的对象或属于左侧的对象,则返回true。

For instance, it can be used to test if an object is an instance of a class (or one of its subclasses).

例如,它可以用来测试一个对象是否是一个类(或其子类之一)的实例。
String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true
           

The same result can be achieved with other methods which are probably best suited for the job.

使用其他可能最适合该工作的方法可以实现相同的结果。

It's usually better to write code that is easy to read by being as explicit as possible, without sacrificing efficiency and conciseness.

通常最好编写尽可能清晰的代码,以使其易于阅读,而不牺牲效率和简洁性。
2.is_a? Integer   # Output: => true
2.kind_of? Integer  # Output: => true
2.instance_of? Integer # Output: => false
           

Notice the last example returned false because integers such as 2 are instances of the Fixnum class, which is a subclass of the Integer class.

请注意,最后一个示例返回false,因为诸如2之类的整数是Fixnum类的实例,而Fixnum类是Integer类的子类。

The ===, is_a?

===,is_a?

and instance_of?

和instance_of?

methods return true if the object is an instance of the given class or any subclasses.

如果对象是给定类或任何子类的实例,则方法返回true。

The instance_of method is stricter and only returns true if the object is an instance of that exact class, not a subclass.

instance_of方法更为严格,并且仅当对象是该确切类的实例而不是子类的实例时才返回true。

The is_a?

is_a?

and kind_of?

和kind_of?

methods are implemented in the Kernel module, which is mixed in by the Object class.

方法在内核模块中实现,该模块由Object类混合。

Both are aliases to the same method.

两者都是同一方法的别名。

Let's verify:

让我们验证一下:

Kernel.instance_method(:kind_of?) == Kernel.instance_method(:is_a?) # Output: => true

Kernel.instance_method(:kind_of?)== Kernel.instance_method(:is_a?)#输出:=> true

Range Implementation of === 范围实现===

When the === operator is called on a range object, it returns true if the value on the right falls within the range on the left.

在范围对象上调用===运算符时,如果右侧的值落在左侧的范围内,则它返回true。
(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
           

Remember that the === operator invokes the === method of the left-hand object.

请记住,===运算符会调用左侧对象的===方法。

So (1..4) === 3 is equivalent to (1..4).=== 3. In other words, the class of the left-hand operand will define which implementation of the === method will be called, so the operand positions are not interchangeable.

因此(1..4)=== 3等于(1..4)。===3。换句话说,左侧操作数的类将定义===方法的哪种实现调用,因此操作数位置不可互换。

Regexp Implementation of === 正则表达式的===实现

Returns true if the string on the right matches the regular expression on the left.

如果右侧的字符串与左侧的正则表达式匹配,则返回true。

/zen/ === "practice zazen today" # Output: => true # is the same as "practice zazen today"=~ /zen/

/ zen / ===“今天练习zazen”#输出:=> true#与“今天练习zazen”相同== / zen /

Implicit usage of the === operator on case/when statements 在case / when语句中===运算符的隐式用法

This operator is also used under the hood on case/when statements.

此操作符还用于case / when语句的内部。

That is its most common use.

这是其最常见的用法。
minutes = 15

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

# Output: match
           

In the example above, if Ruby had implicitly used the double equal operator (==), the range 10..20 would not be considered equal to an integer such as 15. They match because the triple equal operator (===) is implicitly used in all case/when statements.

在上面的示例中,如果Ruby隐式使用了double equal运算符(==),则范围10..20将不被视为等于诸如15的整数。之所以匹配,是因为Triple equal运算符(===)为在所有case / when语句中隐式使用。

The code in the example above is equivalent to:

上面示例中的代码等效于:
if (10..20) === minutes
  puts "match"
else
  puts "no match"
end
           

Pattern matching operators: =~ and !~ 模式匹配运算符:=〜和!〜

The =~ (equal-tilde) and !~ (bang-tilde) operators are used to match strings and symbols against regex patterns.

=〜(等于波浪号)和!〜(大波浪号)运算符用于将字符串和符号与正则表达式模式进行匹配。

The implementation of the =~ method in the String and Symbol classes expects a regular expression (an instance of the Regexp class) as an argument.

String和Symbol类中==方法的实现期望使用正则表达式(Regexp类的实例)作为参数。
"practice zazen" =~ /zen/   # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil

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

The implementation in the Regexp class expects a string or a symbol as an argument.

Regexp类中的实现期望将字符串或符号作为参数。
/zen/ =~ "practice zazen"  # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil
           

In all implementations, when the string or symbol matches the Regexp pattern, it returns an integer which is the position (index) of the match.

在所有实现中,当字符串或符号与Regexp模式匹配时,它将返回一个整数,该整数是匹配项的位置(索引)。

If there is no match, it returns nil.

如果不匹配,则返回nil。

Remember that, in Ruby, any integer value is "truthy" and nil is "falsy", so the =~ operator can be used in if statements and ternary operators.

请记住,在Ruby中,任何整数值都是“ truthy”,而nil是“ falsy”,因此=〜运算符可用于if语句和三元运算符。
puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes
           

Pattern-matching operators are also useful for writing shorter if statements.

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

Example:

例:
if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin"
  true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
  true
end
           

The !~ operator is the opposite of =~, it returns true when there is no match and false if there is a match.

!〜运算符与=〜相反,当没有匹配项时返回true,在有匹配项时返回false。

More info is available at this blog post .

有关更多信息, 请参见此博客文章 。