equal?、eql?、=== 和 == 之间有什么区别?

发布于 2024-12-01 01:50:04 字数 370 浏览 1 评论 0原文

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

=== 默认情况下也会调用 == ,后者调用 equal?...好吧,所以如果这三个方法都没有被重写,那么我猜 =====equal? 做的事情完全相同吗?

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

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

I am trying to understand the difference between these four methods. I know by default that == calls the method equal? which returns true when both operands refer to exactly the same object.

=== by default also calls == which calls equal?... okay, so if all these three methods are not overridden, then I guess
===, == and equal? do exactly the same thing?

Now comes eql?. What does this do (by default)? Does it make a call to the operand's hash/id?

Why does Ruby have so many equality signs? Are they supposed to differ in semantics?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

桃气十足 2024-12-08 01:50:05

相等运算符:== 和 !=

== 运算符也称为相等或双重相等,如果两个对象相等则返回 true,否则返回 false。

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

!= 运算符也称为不等式,与 == 相反。如果两个对象不相等,则返回 true;如果相等,则返回 false。

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

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

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

2 == 2.0 # Output: => true

平等的?

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

例子:
一个=“禅宗”
b = "zen"

a.object_id  # Output: => 20139460
b.object_id  # Output :=> 19972120

a.equal? b  # Output: => false

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

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

a = "zen"
b = a

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

a.equal? b  # Output: => true

情商?

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

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

"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547

hash 方法在 Kernel 模块中实现,包含在 Object 类中,该类是所有 Ruby 对象的默认根。一些类(例如 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

在 Ruby 中,当我们将某些内容存储在哈希(集合)中时,作为键提供的对象(例如字符串或符号)将被转换为哈希码并存储。稍后,当从哈希(集合)中检索元素时,我们提供一个对象作为键,该对象被转换为哈希码并与现有键进行比较。如果匹配,则返回相应项的值。使用 eql? 进行比较方法在幕后。

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

在大多数情况下,eql?方法的行为与 == 方法类似。然而,也有一些例外。例如,eql?将整数与浮点数进行比较时,不执行隐式类型转换。

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

大小写相等运算符:===

许多 Ruby 的内置类(例如 String、Range 和 Regexp)都提供了自己的 === 运算符实现,也称为大小写相等、三重等于或三等式。由于它在每个类中的实现方式不同,因此根据调用它的对象类型,它的行为也会有所不同。一般来说,如果右侧的对象“属于”左侧的对象或“是其成员”,则返回 true。例如,它可用于测试对象是否是类(或其子类之一)的实例。

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

使用可能最适合该工作的其他方法也可以实现相同的结果。通常最好是在不牺牲效率和简洁性的情况下,尽可能明确地编写易于阅读的代码。

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

请注意,最后一个示例返回 false,因为诸如 2 之类的整数是 Fixnum 类的实例,而 Fixnum 类是 Integer 类的子类。 ===,is_a?和instance_of?如果对象是给定类或任何子类的实例,方法将返回 true。 instance_of 方法更严格,仅当对象是该确切类的实例而不是子类时才返回 true。

is_a?和种类?方法在 Kernel 模块中实现,并由 Object 类混合。两者都是同一方法的别名。让我们验证一下:

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

Range === 的实现

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

请记住, === 运算符调用左侧对象的 === 方法。因此 (1..4) === 3 等价于 (1..4).=== 3。换句话说,左侧操作数的类将定义 === 方法的实现被调用,因此操作数位置不可互换。

=== 的 Regexp 实现

如果右侧的字符串与左侧的正则表达式匹配,则返回 true。
/zen/ === "今天练习坐禅" # 输出: =>真的
# 与
"practice zazen Today"=~ /zen/

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

该运算符也在 case/when 语句的幕后使用。这是它最常见的用途。

minutes = 15

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

# Output: match

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

if (10..20) === minutes
  puts "match"
else
  puts "no match"
end

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

=~(等代号)和 !~(bang-代号)运算符用于将字符串和符号与正则表达式模式进行匹配。

String 和 Symbol 类中 =~ 方法的实现需要一个正则表达式(Regexp 类的实例)作为参数。

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

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

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

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

在所有实现中,当字符串或符号与正则表达式模式匹配时,它返回一个整数,即匹配的位置(索引)。如果没有匹配,则返回 nil。请记住,在 Ruby 中,任何整数值都是“真”,而 nil 是“假”,因此 =~ 运算符可以在 if 语句和三元运算符中使用。

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

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

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

!~ 运算符与 =~ 相反,如果不匹配则返回 true,如果匹配则返回 false。

如需了解更多信息,请访问此博文

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.

"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.

"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 (e.g., integer and float), if their numeric value is the same, == will return 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. This is the strictest form of equality in Ruby.

Example:
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. Hence, the equal? method will return false.

Let's try again, only this time b will be a reference to a. Notice that the object ID is the same for both variables, as they point to the same object.

a = "zen"
b = a

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

a.equal? b  # Output: => true

eql?

In the Hash class, the 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. 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. 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. In the context of Ruby programming, the word hash almost always refers to the dictionary-like collection.

Ruby provides a built-in method called hash for generating hashcodes. 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).

"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. Some classes such as Symbol and Integer use the default implementation, others like String and Hash provide their own implementations.

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 (e.g., string or symbol) is converted into and stored as a hashcode. 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? method under the hood.

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

In most cases, the eql? method behaves similarly to the == method. However, there are a few exceptions. For instance, 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. 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. 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. The ===, is_a? and instance_of? methods return true if the object is an instance of the given class or any subclasses. The instance_of method is stricter and only returns true if the object is an instance of that exact class, not a subclass.

The is_a? and kind_of? methods are implemented in the Kernel module, which is mixed in by the Object class. Both are aliases to the same method. Let's verify:

Kernel.instance_method(:kind_of?) == Kernel.instance_method(:is_a?) # Output: => 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.

(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.

Regexp Implementation of ===

Returns true if the string on the right matches the regular expression on the left.
/zen/ === "practice zazen today" # Output: => true
# is the same as
"practice zazen today"=~ /zen/

Implicit usage of the === operator on case/when statements

This operator is also used under the hood on case/when statements. 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. 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.

"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.

/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. If there is no match, it returns 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.

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

Pattern-matching operators are also useful for writing shorter if statements. 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.

More info is available at this blog post.

浅笑轻吟梦一曲 2024-12-08 01:50:05

我想扩展 === 运算符。

=== 不是相等运算符!

不是。

让我们真正了解这一点。

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

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

=== 是模式匹配运算符!

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

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

  • Enumerable#grep 在内部使用 ===
  • case when 语句在内部使用 ===
  • 有趣的事实,rescue 在内部使用 ===

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

一些示例

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 方法。

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]

I would like to expand on the === operator.

=== is not an equality operator!

Not.

Let's get that point really across.

You might be familiar with === as an equality operator in Javascript and PHP, but this just not an equality operator in Ruby and has fundamentally different semantics.

So what does === do?

=== is the pattern matching operator!

  • === matches regular expressions
  • === checks range membership
  • === checks being instance of a class
  • === calls lambda expressions
  • === sometimes checks equality, but mostly it does not

So how does this madness make sense?

  • Enumerable#grep uses === internally
  • case when statements use === internally
  • Fun fact, rescue uses === internally

That is why you can use regular expressions and classes and ranges and even lambda expressions in a case when statement.

Some examples

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

All these example work with pattern === value too, as well as with grep method.

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]
作死小能手 2024-12-08 01:50:05

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

希望对其他人有帮助。

Ruby exposes several different methods for handling equality:

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

Hope it helps others.

奶气 2024-12-08 01:50:05

=== #---case equals

== #--- generic equals

两者的工作原理相似,但“===”甚至 case 语句

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

这里是区别

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

=== #---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
半山落雨半山空 2024-12-08 01:50:05
  1. .eql? - 如果接收者和参数具有相同的类型和相等的值,则此运算符返回 true。

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

  1. === - 它将测试 case 语句中的相等性。

例如 - (1...10) === 1 is true

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

例如 - (1...10) == 1 为 false

了解更多示例 点击此处

  1. .eql? - This operator returns true if the receiver and argument have both the same type and equal values.

for example - 10.eql?(10.0) is false.

  1. === - it will test equality in case statement.

for example - (1...10) === 1 is true

  1. == - This operator checks whether the two given operands are equal or not. If equals, it returns TRUE, Otherwise it returns FALSE.

for example - (1...10) == 1 is false

for more example click here

赴月观长安 2024-12-08 01:50:05

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

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)

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)
呆橘 2024-12-08 01:50:04

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

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

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}

== — 通用“相等”

在对象级别,仅当 objother 是同一对象时,== 返回 true。通常,在后代类中重写此方法以提供特定于类的含义。

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

=== — 大小写相等

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

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

  • Range
  • Regex
  • 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 可以使代码更加简洁。当然,通过提供您自己的 === 实现,您可以获得自定义 case 语义。

eql?哈希 相等性

如果 objother 引用相同的哈希键,eql? 方法将返回 true。 Hash 使用它来测试成员的相等性。 对于Object类的对象,eql?==同义。子类通常通过别名< code>eql? 到其重写的 == 方法,但也有例外。例如,Numeric 类型可以跨 == 执行类型转换,但不能跨 eql? 执行类型转换,因此:

<前><代码>1 == 1.0 #=>真的
1.eql? 1.0#=>错误的

因此您可以随意覆盖此设置供您自己使用,或者您可以覆盖 == 并使用 alias :eql? :== 所以这两个方法的行为方式相同。

equal? — 身份比较

== 不同,equal? 方法永远不应该被子类重写:它用于确定对象标识(即 a.equal? (b) 当且仅当 ab 是同一对象)。

这实际上是指针比较。

I'm going to heavily quote the Object documentation here, because I think it has some great explanations. I encourage you to read it, and also the documentation for these methods as they're overridden in other classes, like String.

Side note: if you want to try these out for yourself on different objects, use something like this:

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}

== — generic "equality"

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.

This is the most common comparison, and thus the most fundamental place where you (as the author of a class) get to decide if two objects are "equal" or not.

=== — case equality

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

This is incredibly useful. Examples of things which have interesting === implementations:

  • Range
  • Regex
  • Proc (in Ruby 1.9)

So you can do things like:

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

See my answer here for a neat example of how case+Regex can make code a lot cleaner. And of course, by providing your own === implementation, you can get custom case semantics.

eql?Hash equality

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 == 1.0     #=> true
1.eql? 1.0   #=> false

So you're free to override this for your own uses, or you can override == and use alias :eql? :== so the two methods behave the same way.

equal? — identity comparison

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).

This is effectively pointer comparison.

超可爱的懒熊 2024-12-08 01:50:04

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

==, ===, eql?< /code>,等于?
是 4 个比较器,即在 Ruby 中比较 2 个对象的 4 种方法。
由于在 Ruby 中,所有比较器(以及大多数运算符)实际上都是方法调用,因此您可以自己更改、覆盖和定义这些比较方法的语义。然而,重要的是要了解,Ruby 的内部语言构造何时使用哪个比较器:

==(值比较)
Ruby 在任何地方都使用 :== 来比较 2 个对象的,例如。哈希值:

{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

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

==, ===, eql?, equal?
are 4 comparators, ie. 4 ways to compare 2 objects, in Ruby.
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. However, it is important to understand, when Ruby's internal language constructs use which comparator:

== (value comparison)
Ruby uses :== everywhere to compare the values of 2 objects, eg. Hash-values:

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

=== (case comparison)
Ruby uses :=== in case/when constructs. 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? (in combination with the method hash) to compare Hash-keys. In most classes :eql? is identical with :==.
Knowledge about :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.

equal? (object identity comparison)
Ruby uses :equal? to check if two objects are identical. This method (of class BasicObject) is not supposed to be overwritten.

obj = obj2 = 'a'
obj.equal? obj2       # => true
obj.equal? obj.dup    # => false
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文