等于?,eql?,===和==有什么区别?

我想了解这四种方法之间的区别。 我知道默认==调用方法equal? 当两个操作数引用完全相同的对象时,它将返回true。

===默认情况下也调用==哪个调用equal? …好的,所以如果所有这三种方法都不覆盖,那么我猜=====equal? 做同样的事情?

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

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

我将在这里大量引用Object文档 ,因为我认为它有一些很好的解释。 我鼓励你阅读它,以及这些方法的文档,因为它们在其他类中被重写,比如String 。

注意:如果你想在不同的物体上尝试这些,请使用下面的内容:

 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语句中提供有意义的语义。

这非常有用。 有趣的===实现的东西的例子:

  • 范围
  • 正则expression式
  • 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?Hash平等

eql? 方法返回true,如果objother引用相同的散列键。 这被Hash用来testing成员的平等。 对于Object类的Objecteql? ==同义词。 子类通常通过别名eql?inheritance这个传统eql? 到他们重写的==方法,但也有例外。 例如, Numerictypes在整个==执行types转换,但是不在整个eql? ,所以:

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

所以你可以自由地覆盖这个你自己的用途,或者你可以覆盖==和使用alias :eql? :== alias :eql? :==所以这两个方法的行为是一样的。

equal? – 身份比较

不像==equal? 方法不应被子类覆盖:它用于确定对象标识(即, a.equal?(b) iff ab相同)。

这是有效的指针比较。

我爱jtbandes的答案,但由于它很长,我会添加我自己的紧凑答案:

=====eql? equal?
是4比较,即。 在Ruby中比较两个对象的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的知识? 只有当你想创build自己的特殊类时才是重要的:

 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类Set也依赖于哈希键比较。

equal? (对象身份比较)
Ruby使用:相等? 检查两个对象是否相同。 这个(BasicObject类的)方法不应该被覆盖。

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

平等操作符:==和!=

==运算符(也称为equals或double equal)将在两个对象相等时返回true,否则返回false。

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

!=运算符AKA不等式或bang-tilde与==相反。 如果两个对象不相等,则返回true,如果相等,则返回false。

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

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

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

 2 == 2.0 # Output: => true 

等于?

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

例如:a =“zen”b =“zen”

 a.object_id # Output: => 20139460 b.object_id # Output :=> 19972120 a.equal? b # Output: => false 

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

让我们再试一次,只有这个时候b会是一个参考。 请注意,两个variables的对象ID是相同的,因为它们指向相同的对象。

 a = "zen" b = a a.object_id # Output: => 18637360 b.object_id # Output: => 18637360 a.equal? b # Output: => true 

EQL?

在Hash类中,eql? 方法是用来testing键是否相等。 需要一些背景来解释这一点。 在计算的一般环境中,散列函数采用任意大小的string(或文件),并生成称为散列码的固定大小的string或整数,通常称为散列。 一些常用的散列码types是MD5,SHA-1和CRC。 它们用于encryptionalgorithm,数据库索引,文件完整性检查等。一些编程语言(如Ruby)提供了一个称为哈希表的集合types。 散列表是类似字典的集合,它们成对存储数据,由唯一键和相应的值组成。 在引擎盖下,这些键被存储为散列码。 散列表通常被称为散列。 注意hashcan这个词是指一个哈希码还是一个哈希表。 在Ruby编程环境中,hash这个词几乎总是指字典式的集合。

Ruby提供了一个称为hash的内置方法来生成hashcode。 在下面的例子中,它需要一个string并返回一个哈希码。 注意具有相同值的string总是具有相同的哈希码,尽pipe它们是不同的对象(具有不同的对象ID)。

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

散列方法在包含在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中,当我们将某些东西存储在散列(集合)中时,作为键(例如string或符号)提供的对象被转换并存储为散列码。 后来,当从哈希(集合)中检索一个元素时,我们提供一个对象作为关键字,将其转换为哈希码并与现有关键字进行比较。 如果匹配,则返回相应项目的值。 比较是使用eql? 引擎盖下的方法。

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

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

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

案例相等运算符:===

许多Ruby的内置类(如String,Range和Regexp)提供了===运算符(也称为case-equality,triple equals或threequals)的自己的实现。 因为它在每个类中都以不同的方式实现,所以它将根据所调用的对象的types而有所不同。 通常,如果右侧的对象“属于”或“是左侧的对象的成员”,则返回true。 例如,它可以用来testing一个对象是否是一个类的实例(或者它的一个子类)。

 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? 方法在内核模块中实现,由Object类混合。 两者都是相同方法的别名。 我们来validation一下:

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

===的范围实现

当在范围对象上调用===运算符时,如果右边的值落在左边的范围内,则返回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.换句话说,左边操作数的类将定义===方法的实现是所谓的操作数位置是不可互换的。

正则expression式实现===

如果右侧的string与左侧的正则expression式匹配,则返回true。 / zen / ===“今天的练习zazen”#输出:=> true#和“今天的练习zazen”=〜/ 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这样的整数。它们匹配是因为三等号(===)是隐含地用在所有情况下/当语句。 上例中的代码相当于:

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

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

使用=〜(等于波浪号)和!〜(bang-tilde)运算符来匹配正则expression式模式的string和符号。

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

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

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

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

在所有实现中,当string或符号匹配正则expression式模式时,它返回一个整数,它是匹配的位置(索引)。 如果不匹配,则返回nil。 请记住,在Ruby中,任何整数值都是“truthy”,而nil是“falsy”,因此可以在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。

更多信息可在此博客文章 。

===#—案件平等

==#—通用的平等

两者的作品相似,但“===”甚至做个案陈述

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

这里的区别

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

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

a.equal?(b)#对象标识 – a和b是指同一个对象

a.eql?(b)#对象等价 – a和b具有相同的值

a == b#对象等价 – a和b与types转换具有相同的值。

点击下面的链接继续阅读,这给了我一个明确的总结了解。

https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers

希望它可以帮助别人。

我想展开===运算符。

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

不。

让我们来看看这个点。

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

那么===做什么的?

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

  • ===匹配正则expression式
  • ===检查范围成员资格
  • ===检查是一个类的实例
  • ===调用lambdaexpression式
  • ===有时会检查平等,但大多数情况下不会

那么这个疯狂怎么有意义?

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

这就是为什么你可以使用正则expression式和类和范围,甚至case when语句case when lambdaexpression式。

一些例子

 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] 

我为所有上面写了一个简单的testing。

 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)