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

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

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

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


当前回答

=== #——大小写相等

== #——一般相等

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

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

区别就在这里

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

其他回答

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

希望它能帮助别人。

=== #——大小写相等

== #——一般相等

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

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

区别就在这里

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

我想扩展一下===运算符。

===不是相等运算符!

Not.

让我们把这一点讲清楚。

在Javascript和PHP中,===可能是一个相等操作符,但在Ruby中,这不是一个相等操作符,并且具有根本不同的语义。

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

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

===匹配正则表达式 ===检查范围成员关系 ===检查是否是类的实例 ===调用lambda表达式 ===有时可以检查是否相等,但大多数情况下不能

那么,这种疯狂是怎么说得通的呢?

可枚举#grep在内部使用=== 语句内部使用===的情况 有趣的是,救援在内部使用===

这就是为什么在语句中可以使用正则表达式、类和范围,甚至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]

我喜欢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

相等运算符:==和!=

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

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

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

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

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

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

2 == 2.0 # Output: => true

等于多少?

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

例子: A = "zen" 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

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提供了一种称为hash的内置方法来生成hashcode。在下面的例子中,它接受一个字符串并返回一个hashcode。请注意具有相同值的字符串总是具有相同的hashcode,即使它们是不同的对象(具有不同的对象id)。

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

哈希方法是在Kernel模块中实现的,包含在Object类中,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中,当我们在哈希(集合)中存储一些东西时,作为键提供的对象(例如,字符串或符号)将被转换为哈希代码并存储为哈希代码。稍后,当从散列(集合)中检索元素时,我们提供一个对象作为键,该键被转换为hashcode并与现有键进行比较。如果匹配,则返回对应项的值。使用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

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

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

用其他可能最适合这项工作的方法也能达到同样的结果。通常,在不牺牲效率和简明性的情况下,尽可能明确地编写易于阅读的代码会更好。

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

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

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

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

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。换句话说,左操作数的类将定义将调用===方法的哪个实现,因此操作数的位置是不可互换的。

===的实现

如果右边的字符串与左边的正则表达式匹配,则返回true。 /zen/ === "practice zazen today" #输出:=> true #和 “今天练坐禅”=~ /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

模式匹配操作符:=~和

=~ (equal-tilde)和!~ (bang-tilde)操作符用于根据正则表达式模式匹配字符串和符号。

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

在所有实现中,当字符串或符号匹配Regexp模式时,它将返回一个整数,该整数是匹配的位置(索引)。如果没有匹配,则返回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。

更多信息可以在这篇博客文章中找到。