equal?、eql?、=== 和 == 之间有什么区别? [英] What's the difference between equal?, eql?, ===, and ==?

查看:37
本文介绍了equal?、eql?、=== 和 == 之间有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

==== 默认也调用 == 调用 equal?... 好吧,如果这三个方法都不是被覆盖,那么我猜====, ==equal? 做的完全一样吗?

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

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

解决方案

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

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

class 对象def all_equals(o)ops = [:==, :===, :eql?, :equal?]哈希[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]结尾结尾a".all_equals a"# =>{=="=>真,==="=>真,eql?"=>真,等于?"=>假}


== — 通用的相等"

<块引用>

在对象级别,仅当 objother 是同一个对象时,== 才返回 true.通常,此方法在后代类中被覆盖以提供特定于类的含义.

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

==== — 大小写相等

<块引用>

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

这非常有用.具有有趣的 === 实现的事物示例:

  • 范围
  • 正则表达式
  • Proc(在 Ruby 1.9 中)

因此您可以执行以下操作:

case some_object当/a 正则表达式/# 正则匹配当 2..4# some_object 在 2..4 范围内当 lambda {|x|some_crazy_custom_predicate }# lambda 返回真结尾

请参阅我在此处的回答case+Regex 如何让代码更简洁的一个很好的例子.当然,通过提供您自己的 === 实现,您可以获得自定义的 case 语义.

eql?Hash 等式

<块引用>

如果 objother 引用相同的哈希键,则 eql? 方法返回 true.Hash 使用它来测试成员是否相等.对于 Object 类的对象,eql?== 的同义词. 子类通常通过别名 eql? 到他们重写的 == 方法,但也有例外.Numeric 类型,例如跨==进行类型转换,但不跨eql?,所以:

1 == 1.0 #=>真的1.eql?1.0 #=>错误的

所以你可以自由地覆盖它以供你自己使用,或者你可以覆盖 == 并使用 alias :eql?:== 所以这两种方法的行为方式相同.

equal? — 身份比较

<块引用>

== 不同,equal? 方法不应该被子类覆盖:它用于确定对象身份(即 a.equal?(b)ab 是同一个对象.

这是有效的指针比较.

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?

解决方案

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.

这篇关于equal?、eql?、=== 和 == 之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆