equal?,eql?,===和==之間有什麼區別?

本文翻譯自: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 . 有關更多信息, 請參見此博客文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章