我试图了解这四种方法之间的区别。我知道默认情况下,当两个操作数都引用完全相同的对象时,它会==调用返回 true 的方法。equal?
==
equal?
===默认情况下还会调用==which call equal?… 好吧,所以如果所有这三个方法都没有被覆盖,那么我猜 ===,==并且equal?做同样的事情?
===
现在来了eql?。这是做什么的(默认情况下)?它会调用操作数的哈希/ID吗?
eql?
为什么 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}
在对象级别,仅当和是同一个对象==时才返回 true 。通常,此方法在后代类中被覆盖以提供特定于类的含义。obj``other
obj``other
这是最常见的比较,因此是您(作为类的作者)决定两个对象是否“相等”的最基本的地方。
对于类 Object,实际上与 call 相同#==,但通常被后代覆盖以在 case 语句中提供有意义的语义。
#==
这非常有用。具有有趣===实现的事物示例:
因此,您可以执行以下操作:
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
case``Regex``===``case
eql?``Hash
如果和引用相同的哈希键,该eql?方法返回 true 。这用于测试成员是否相等。 对于类的对象 , 是 的同义词 。 子类通常通过为其覆盖的方法起别名来延续这一传统,但也有例外。例如,types 执行类型转换 across ,而不是 across ,所以:obj``other``Hash Object``eql?``==eql?``==``Numeric``==``eql? 1 == 1.0 #=> true 1.eql? 1.0 #=> false
如果和引用相同的哈希键,该eql?方法返回 true 。这用于测试成员是否相等。 对于类的对象 , 是 的同义词 。 子类通常通过为其覆盖的方法起别名来延续这一传统,但也有例外。例如,types 执行类型转换 across ,而不是 across ,所以:obj``other``Hash Object``eql?``==eql?``==``Numeric``==``eql?
obj``other``Hash
Object``eql?``==
eql?``==``Numeric``==``eql?
1 == 1.0 #=> true 1.eql? 1.0 #=> false
因此,您可以自由地覆盖它以供自己使用,或者您可以覆盖==并使用alias :eql? :==,因此这两种方法的行为方式相同。
alias :eql? :==
与 不同==的是,该equal?方法永远不应该被子类覆盖:它用于确定对象身份(即a.equal?(b)iffa是与 相同的对象b)。
a.equal?(b)
a
b
这实际上是指针比较。