What's the difference between equal?, eql?, ===, and ==?
我试图理解这四种方法之间的区别。我知道默认情况下,
默认情况下,
现在来了。这有什么作用(默认情况下)?它是否调用操作数的哈希/id?
为什么Ruby有这么多平等的标志?他们应该在语义上有所不同吗?
我将在这里大量引用对象文档,因为我认为它有一些很好的解释。我鼓励您阅读它,以及这些方法的文档,因为它们在其他类(如字符串)中被重写。
旁注:如果您想在不同的对象上自己尝试这些方法,请使用如下方法:
1 2 3 4 5 6 7 8 | 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} |
At the Object level,
== returns true only ifobj andother are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.
这是最常见的比较,也是(作为类的作者)决定两个对象是否"相等"的最基本的地方。
For class Object, effectively the same as calling
#== , but typically overridden by descendants to provide meaningful semantics in case statements.
这是非常有用的。有趣的
- 范围
- 正则表达式
- proc(在ruby 1.9中)
所以你可以这样做:
1 2 3 4 5 6 7 8 | 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 |
请看我的答案,以获得一个很好的例子,说明
The
eql? method returns true ifobj andother refer to the same hash key. This is used byHash to test members for equality. For objects of classObject ,eql? is synonymous with== . Subclasses normally continue this tradition by aliasingeql? to their overridden== method, but there are exceptions.Numeric types, for example, perform type conversion across== , but not acrosseql? , so:
1
2 1 == 1.0 #=> true
1.eql? 1.0 #=> false
所以您可以自由地为自己的使用而重写它,或者您可以重写
Unlike
== , theequal? method should never be overridden by subclasses: it is used to determine object identity (that is,a.equal?(b) iffa is the same object asb ).
这实际上是指针比较。
我喜欢JTBandes答案,但由于它很长,我将添加我自己的简洁答案:
1 2 | {a: 'z'} == {a: 'Z'} # => false {a: 1} == {a: 1.0} # => true |
1 2 3 4 5 6 7 | case foo when bar; p 'do something' end if bar === foo p 'do something' end |
1 2 3 4 5 6 7 8 9 10 | 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类集还依赖于哈希键比较。
1 2 3 | obj = obj2 = 'a' obj.equal? obj2 # => true obj.equal? obj.dup # => false |
相等运算符:==和!=
==运算符,也称为equality或double equal,如果两个对象相等,则返回true;否则返回false。好的。
1 | "koan" =="koan" # Output: => true |
这个!=运算符,也称为不等式,与==相反。如果两个对象不相等,则返回"真";如果两个对象相等,则返回"假"。好的。
1 | "koan" !="discursive thought" # Output: => true |
请注意,两个元素顺序不同的数组是不相等的,同一字母的大小写版本是不相等的,依此类推。好的。
当比较不同类型的数字(例如整数和浮点)时,如果它们的数值相同,==将返回真。好的。
1 | 2 == 2.0 # Output: => true |
相等?
与测试两个操作数是否相等的==运算符不同,equal方法检查两个操作数是否引用同一对象。这是Ruby中最严格的平等形式。好的。
例子:"禅""禅"好的。
1 2 3 4 | a.object_id # Output: => 20139460 b.object_id # Output :=> 19972120 a.equal? b # Output: => false |
在上面的示例中,我们有两个值相同的字符串。但是,它们是两个不同的对象,具有不同的对象ID。因此,平等?方法将返回false。好的。
让我们再试一次,只是这次b将是对a的引用。请注意,两个变量的对象ID是相同的,因为它们指向同一个对象。好的。
1 2 3 4 5 6 7 | a ="zen" b = a a.object_id # Output: => 18637360 b.object_id # Output: => 18637360 a.equal? b # Output: => true |
EQL?
在hash类中,eql?方法用于测试键是否相等。需要一些背景来解释这一点。在计算的一般上下文中,哈希函数接受任意大小的字符串(或文件),并生成一个固定大小的字符串或整数,称为hashcode,通常称为only hash。一些常用的哈希代码类型是MD5、SHA-1和CRC。它们用于加密算法、数据库索引、文件完整性检查等。一些编程语言(如Ruby)提供一种称为哈希表的集合类型。哈希表是类似字典的集合,成对存储数据,由唯一键及其对应值组成。在发动机罩下,这些钥匙存储为哈希代码。哈希表通常只被称为哈希表。注意单词hashcan如何引用哈希代码或哈希表。在Ruby编程的上下文中,单词hash几乎总是指类似字典的集合。好的。
Ruby提供了一个名为hash的内置方法来生成哈希代码。在下面的示例中,它接受一个字符串并返回一个哈希代码。请注意,具有相同值的字符串总是具有相同的哈希代码,即使它们是不同的对象(具有不同的对象ID)。好的。
1 2 3 | "meditation".hash # Output: => 1396080688894079547 "meditation".hash # Output: => 1396080688894079547 "meditation".hash # Output: => 1396080688894079547 |
哈希方法在内核模块中实现,包含在对象类中,对象类是所有Ruby对象的默认根。一些类(如symbol和integer)使用默认实现,其他类(如string和hash)提供自己的实现。好的。
1 2 3 4 5 | 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中,商店的东西在hash(collection),AS(the Key对象提供,如字符串或符号)和存储转换into is as a的hash码。当查询后,安元(collection)from the hash对象,我们提供安as a key,which is into a转换compared to the existing hashCode和钥匙。if there is the value of the match,对应item is returned。is using the EQL比较自制的茶?在罩的方法。>
1 2 3 | "zen".eql?"zen" # Output: => true # is the same as "zen".hash =="zen".hash # Output: => true |
在the most cases,EQL?behaves similarly method to the method = =。不管一个人多了一些,there are。for instance,EQL?does not做隐式转换时,an integer型浮法to a?比较。>
1 2 3 | 2 == 2.0 # Output: => true 2.eql? 2.0 # Output: => false 2.hash == 2.0.hash # Output: => false |
家庭平等社:===
在S -红宝石many of such as新建类,字符串,布尔表达式,范围,提供他们自己的implementations = of the known as operator,房子也threequals平等,等于前三。因为它要实现在每一页differently舱,将常用differently depending on the type of object was called恩先生generally归来true if the object,它由"belongs to the right"或"is of the对象成员的"on the left。for instance,it can be used to an object is an instance测试if(or of a class one of its subclasses)。>
1 2 3 4 | String ==="zen" # Output: => true Range === (1..2) # Output: => true Array === [1,2,3] # Output: => true Integer === 2 # Output: => true |
result can be the same with other which are probably方法实现最佳suited for the job。这是更好的usually that is to write队列读易"as as possible显式模式,在效率和conciseness sacrificing。>
1 2 3 | 2.is_a? Integer # Output: => true 2.kind_of? Integer # Output: => true 2.instance_of? Integer # Output: => false |
通知我integers returned the last example such as 2是错误的情况下,fixnum of the class,which is a class of the subclass integer。===_ is the,a?_和instance of?方法返回true if the object is an instance of the class or any given subclasses。_ method is the instance of the true if and only stricter归来is an instance of that精确对象类,subclass not a。>
_ the is?和_ kind of?要实现的方法是在核心模块中,which is the class对象的混合模式。别名to the same method are both。我们的验证:>
kernel.instance _ method(:_ kind of?)kernel.instance(:= _ method is _?)#输出:=>True>
范围= implementation of
when the = is called on a范围内经营者的对象,它返回true if the value on the right on the left the范围内的瀑布。>
1 2 3 4 5 6 | (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 |
记住that the======invokes社the method of the left手对象。我(1 = 4)3(1到4)是等价的。===3。在其他的话,the class of the left手操作数执行of the which will define method = will be called the are not,interchangeable知道操作数的位置。>
regexp implementation of===
返回true if the字符串正则表达式on the right on the left the matches。//=="禅打坐实践=>:今日"#输出true# is the same as"实践禅打坐今日"= ~ / />
在case/when语句上隐式使用===运算符
此运算符也用于"打开案例/时间"语句的软篷下。这是它最常用的用法。好的。
1 2 3 4 5 6 7 8 9 10 | minutes = 15 case minutes when 10..20 puts"match" else puts"no match" end # Output: match |
在上面的示例中,如果Ruby隐式使用了double equal运算符(==),那么范围10..20将不被视为等于整数,如15。它们匹配是因为在所有case/when语句中都隐式使用了三重相等运算符(==)。上面示例中的代码等价于:好的。
1 2 3 4 5 | if (10..20) === minutes puts"match" else puts"no match" end |
模式匹配运算符:=~和!~
=~(等号)和!~(bang tilde)运算符用于根据regex模式匹配字符串和符号。好的。
字符串和符号类中的=~方法的实现需要正则表达式(regexp类的实例)作为参数。好的。
1 2 3 4 5 | "practice zazen" =~ /zen/ # Output: => 11 "practice zazen" =~ /discursive thought/ # Output: => nil :zazen =~ /zen/ # Output: => 2 :zazen =~ /discursive thought/ # Output: => nil |
regexp类中的实现需要一个字符串或符号作为参数。好的。
1 2 | /zen/ =~"practice zazen" # Output: => 11 /zen/ =~"discursive thought" # Output: => nil |
在所有实现中,当字符串或符号与regexp模式匹配时,它返回一个整数,即匹配的位置(索引)。如果没有匹配项,则返回零。记住,在Ruby中,任何整数值都是"truthy",nil是"falsy",因此=~运算符可以用于if语句和三元运算符。好的。
1 2 | puts"yes" if"zazen" =~ /zen/ # Output: => yes "zazen" =~ /zen/?"yes":"no" # Output: => yes |
模式匹配运算符对于编写较短的if语句也很有用。例子:好的。
1 2 3 4 5 6 7 | if meditation_type =="zazen" || meditation_type =="shikantaza" || meditation_type =="kinhin" true end Can be rewritten as: if meditation_type =~ /^(zazen|shikantaza|kinhin)$/ true end |
这个!~ operator与=~相反,如果没有匹配,则返回true;如果有匹配,则返回false。好的。
有关详细信息,请访问此日志。好的。好啊。
我想扩大对
不是。
让我们把这一点讲清楚。
在javascript和php中,您可能熟悉
那么,
=== 匹配正则表达式=== 检查范围成员=== 检查是一个类的实例=== 调用lambda表达式=== 有时检查平等性,但大多数情况下不检查平等性。
那么这种疯狂有什么意义呢?
Enumerable#grep 内部使用=== 。case when 报表内部使用=== 。- 有趣的是,
rescue 在内部使用=== 。
这就是为什么可以在
一些实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
所有这些示例也适用于
1 2 3 4 5 6 7 8 9 | 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] |
Ruby公开了几种处理相等性的不同方法:
1 2 3 4 5 | 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
希望它能帮助别人。
==---大小写相等==---一般相等
两者工作原理相似,但"=="偶数do case语句
1 2 | "test" =="test" #=> true "test" ==="test" #=> true |
这里的区别
1 2 | String ==="test" #=> true String =="test" #=> false |
我为以上所有内容编写了一个简单的测试。
1 2 3 4 5 6 7 8 9 10 11 12 | 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) |