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

===默认情况下还会调用== = 哪些调用equal?...很好,所以如果不重写所有这三种方法,然后我想==== ==equal?做相同的事吗?

现在,到eql?(默认情况),这做什么?操作数的希 /id 对的调用呢?

Ruby 为什么有这么多的相等迹象?他们被应该在语义上不同吗?

2011-08-23 06:13:58
问题评论:

我刚开始 irb 并具有以下与您相矛盾的结果...所有这些 3: "a" == "a""a" === "a""a".eql? "a".但这是不正确︰ "a".equal? "a" (我是 ruby 1.9.2-p180)

@Peter︰ 这是因为字符串重写相等运算符的所有。尝试使用a = Object.new; b = Object.new然后所有=====.equal?.eql?将返回true a vsa和假avs b.

感谢您的说明 !

回答:

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

边注︰ 如果您想要尝试这些方法为自己在不同的对象,可以使用如下所示︰

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。通常,重写此方法在子代类中以提供特定于类的含义。

这是最常用的比较,因而这里您 (作为类的作者) 可以确定两个对象是否"平等"的最基本的地方。

===— — 案例是否相等

类对象,有效地与调用#==,但通常由后代提供有意义的语义 case 语句中被重写。

这是非常有用的。这有有趣的===实现的事情的例子︰

  • 范围
  • 正则表达式
  • 进程内 (在 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用来测试相等的成员。的对象的类Objecteql? ==与同义。子类通常通过别名来继续这种传统eql?对其重写==方法,但也有例外。Numeric类型,例如, ==,在执行类型转换,但不是横向eql?,因此︰

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

因此,您可以自由地重写此对于自己使用,也可以重写== ,使用alias :eql? :==这样的两种方法的行为相同的方式。

equal?— — 标识比较

==equal?绝不应由子类重写方法︰ 它用于确定对象标识 (即a.equal?(b) iffa是与b相同的对象).

这实际上是指针比较。

我知道从您的答案,严格性是︰ 相等?< eql 吗?< = = < ===。通常,使用 = =。对于一些松散的目的,则使用 ===。对于严格的情况下,您使用 eql?,以及完整的标识,使用相等吗?。

严格性的概念不能强制执行或甚至建议的文档中,它就这样发生,Numeric处理它比=== 更严格的方式。实际上是由类的作者。case语句之外,很少使用===

= = 太大/小的相等。即如果包含 Comparable,它将定义在 <> = 返回 0。这是为什么 1 = = 1.0,则返回 true。

@sawa 我通常看作是===的含义与"匹配"(大约)。如在"不 regexp 匹配字符串"或"does 范围匹配 (包括) 数量"。

答得好。它未答复我的一个问题是是否任何这些相等会彼此继承。如果我重新定义 = =,那样改变行为的 === 吗?等方面。播放一些表明 === 采用行为的 = =,而 = = 和 eql 吗?不会相互影响。

我喜欢 jtbandes 的答案,但因为它是很长,我将我自己简洁的答案︰

==, ===, eql?equal?
ie 是 4 comparators。比较 2 的对象,在 Ruby 中的四种方法。
为,在 Ruby 中,所有 comparators (和大多数运算符) 是实际的方法调用,您可以更改、 覆盖,并定义它们自己比较方法的语义。但是,务必要了解,Ruby 的内部语言结构时使用的比较运算符︰

==(值比较)
Ruby 使用: = = 任何地方,如比较 2 的对象的哈希值︰

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

===(大小写的比较)
Ruby 使用: === 在案例/当构造。下面的代码段是以逻辑方式相同︰

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 类集还依赖哈希键比较。

equal?(对象标识比较)
Ruby 使用︰ 相等?若要检查两个对象是否相同。此方法 (BasicObject) 不是被覆盖。

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

它是一个很好的答案,但它是几乎几乎只要 jtbandes 的。:)

=== #---区分大小相等

= = #---泛型相等

这两种工作方式相似,但"==="甚至不要事例语句

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

这里的区别

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

他们起作用,同样,虽然它往往也是如此,当a==b然后a===b但是a===b的功能更加强大。===并不对称,以及a===b意味着很大的不同的事情,从b===a、 单独让a==b.

相等运算符: = = 和 ! =

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

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

! = 运算符,也称为不相等或爆炸以颚化符,= = 的相反。它将返回如果两个对象不相等,如果相等,则返回 true。

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

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

在比较不同类型 (如整数和浮点数) 的数字时其数值是相同的如果 = = 将返回 true。

2 == 2.0 # Output: => true

等?

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

示例︰ ="zen"b ="zen"

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

a.equal? b  # Output: => false

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

让我们再试一次,只是这次 b 将参考答︰ 注意的对象 ID 是相同的两个变量,因为它们指向同一个对象。

a = "zen"
b = a

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

a.equal? b  # Output: => true

eql 吗?

在希类,eql 吗?它用于测试键相等的方法。解释这需要一些背景知识。在常规的计算环境,哈希函数接受任意大小的字符串 (或文件),并生成一个字符串或称为哈希代码,通常称为唯一的哈希的固定大小的整数。某些常用的哈希代码类型是 MD5、 sha-1 和 CRC。它们被用在加密算法,数据库索引、 文件完整性检查,等等。一些编程语言,Ruby,如提供集合类型称为哈希表。哈希表是将数据存储在包含唯一键和及其对应的值对的字典般收藏集。决窍,这些注册表项存储为模数。哈希表通常称为不仅仅是哈希值。请注意 word hashcan 参考的哈希代码或哈希表的参考。在 Ruby 编程的上下文中,字希几乎总是指类似于字典的集合。

Ruby 提供用于生成模数称为哈希的内置方法。在下面的示例中,它接受一个字符串并返回哈希代码。注意如何具有相同值的字符串始终具有相同的哈希代码,即使它们是不同的对象 (具有不同对象 Id)。

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

在内核模块中,包括在对象类中,是所有 Ruby 对象的默认根实现哈希方法。使用默认实现,有些类如符号和整数、 字符串和哈希等其他人提供自己的实现。

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 的内置类、 字符串、 范围和 Regexp,如提供其自己的实现的 === 运算符,也称为案例相等、 三等于或 threequals。因为它在每个类以不同的方式实现,它将采取不同的行为类型的对象调用。通常情况下,它返回 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 类,即整数类的子类的实例。===,is_a?和 instance_of?方法返回对象是否给定的类或任何子类的一个实例,则返回 true。Instance_of 方法较为严格,才会返回 true,如果对象是该类的实例完全相同,没有一个子类。

Is_a?和 kind_of?方法是对象类的混合在内核模块中实现的。两者都是同一个方法的别名。让我们验证︰

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

Regexp 实现 ===

如果右侧的字符串左侧正则表达式匹配,则返回 true。/zen/ ==="今天练习 zazen"# 输出: = > 真 # 等同于"现在的做法 zazen"= ~ /zen/

隐式使用 === 运算符案例/当语句

此运算符也是在汽车发动机罩下上使用案例/如果语句。这就是最常见的用途。

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

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

= ~ (代字号等) 和 ! ~ (爆炸代字号) 运算符用于匹配字符串和正则表达式模式对符号。

实现的 = ~ 的字符串和符号类中的方法要求的正则表达式 (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

在所有实现,当字符串或符号匹配正则表达式模式中,它将返回一个整数,它是匹配的位置 (索引)。如果没有匹配项,则返回零。请记住在 Ruby 中,任何整数值是"truthy",是"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。

更多的信息可在此博客文章.

我发现这更好的答案比目前接受的答案,因为它提供了很好的示例,是关于哪些不同类型的相等平均少明确和它们存在的原因/使用它们的地方。

非常详细的答案,而是在我 irb (ruby v 2.2.1) :zen === "zen"返回 false

@MikeR 感谢您让我知道。我已经更正答案。

Ruby 公开几种不同的方法来处理相等︰

a.equal?(b) # 对象标识-和 b 引用同一个对象

a.eql?(b) # 对象等效性-和 b 具有相同的值

= = b # 对象等效性-和 b 具有相同的值的类型转换。

继续阅读通过单击下面的链接,它给我带来了十分清楚的汇总。

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

希望它可以帮助其他人。

虽然此链接可能回答这些问题,最好包括这里的答案的关键部件,并提供链接供参考。只链接的答案可能会变得无效,如果更改了链接的页面。

请输入您的翻译

What's the difference between equal?, eql?, ===, and ==?

确认取消