我试图理解这四种方法之间的区别。我知道默认情况下==调用方法等于?当两个操作数都指向同一个对象时返回true。
===默认也调用==哪个调用equal?…如果这三个方法都没有被覆盖,那么我猜 ===, == and equal?做完全一样的事情?
现在是eql?。这是做什么(默认情况下)?它是否调用操作数的哈希/id?
为什么Ruby有这么多等号?它们应该在语义上有所不同吗?
我试图理解这四种方法之间的区别。我知道默认情况下==调用方法等于?当两个操作数都指向同一个对象时返回true。
===默认也调用==哪个调用equal?…如果这三个方法都没有被覆盖,那么我猜 ===, == and 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}
== -一般的"平等"
在Object级别,==仅当obj和other是同一个对象时才返回true。通常,这个方法在子类中被重写,以提供特定于类的含义。
这是最常见的比较,因此也是您(作为类的作者)决定两个对象是否“相等”的最基本的地方。
=== - case相等
对于Object类,实际上与调用#==相同,但通常由后代重写,以在case语句中提供有意义的语义。
这是非常有用的。有趣的===实现的例子:
范围 正则表达式 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如何使代码更简洁。当然,通过提供您自己的===实现,您可以获得自定义大小写语义。
eql吗?-哈希等价
eql吗?如果obj和other指向相同的散列键,则方法返回true。Hash使用它来测试成员是否相等。对于Object类的对象,eql?是==的同义词。子类通常通过别名eql?它们被重写的==方法,但也有例外。例如,数值类型跨==执行类型转换,但不跨eql?,所以: 1 == 1.0 #=> true 1. eql ?1.0 #=> false
因此,您可以自由地为自己的用途覆盖它,或者您可以覆盖==并使用别名:eql?:==所以这两个方法的行为是相同的。
等于多少?-身份比较
不像==,相等?方法永远不应该被子类覆盖:它用于确定对象的身份(即a.equal?(b)如果a与b是相同的对象)。
这是有效的指针比较。
其他回答
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
希望它能帮助别人。
我将在这里大量引用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}
== -一般的"平等"
在Object级别,==仅当obj和other是同一个对象时才返回true。通常,这个方法在子类中被重写,以提供特定于类的含义。
这是最常见的比较,因此也是您(作为类的作者)决定两个对象是否“相等”的最基本的地方。
=== - case相等
对于Object类,实际上与调用#==相同,但通常由后代重写,以在case语句中提供有意义的语义。
这是非常有用的。有趣的===实现的例子:
范围 正则表达式 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如何使代码更简洁。当然,通过提供您自己的===实现,您可以获得自定义大小写语义。
eql吗?-哈希等价
eql吗?如果obj和other指向相同的散列键,则方法返回true。Hash使用它来测试成员是否相等。对于Object类的对象,eql?是==的同义词。子类通常通过别名eql?它们被重写的==方法,但也有例外。例如,数值类型跨==执行类型转换,但不跨eql?,所以: 1 == 1.0 #=> true 1. eql ?1.0 #=> false
因此,您可以自由地为自己的用途覆盖它,或者您可以覆盖==并使用别名:eql?:==所以这两个方法的行为是相同的。
等于多少?-身份比较
不像==,相等?方法永远不应该被子类覆盖:它用于确定对象的身份(即a.equal?(b)如果a与b是相同的对象)。
这是有效的指针比较。
.eql吗?—如果接收方和实参具有相同类型且值相等,则此操作符返回true。
例如- 10.eql?(10.0)为假值。
=== -它将在case语句中测试是否相等。
例如-(1…10)=== 1为真
== -该操作符检查两个给定的操作数是否相等。如果等于,则返回TRUE,否则返回FALSE。
例如-(1…10)== 1为假
更多示例请点击这里
我编写了一个简单的测试。
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)
我想扩展一下===运算符。
===不是相等运算符!
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]