Ruby 分析 Ruby 中的比较函数

308820773 · 2016年12月30日 · 最后由 EvanYa 回复于 2017年06月25日 · 4189 次阅读

在学习 spec 的时候,有个 eq 匹配器不是很理解,所以查了下资料. 发现 ruby 中的比较函数,eql? equal? == === is_a? kind_of? instance_of? 傻傻分不清楚。 还有nil? empty? blank? present? 几个函数。也是比较容易引起混淆。

抽时间整理了下,如果有错误,欢迎指正。


eql?

一般情况下,表现与 == 相同。hash 里面 key 的比较,就是采用的这个函数。比如 {1.0 => 'a', 1 =>'b'}, 代表两个不同 key 值。

equal?

用来判定,内存地址相同的对象,使用的时候,不应覆盖此方法。有点类似于 JavaScript 中的 ===. 这里稍微引申下。a = 'b', b = 'b', a.equal?(b) 是返回 false 的,因为定义变量 a, b 的时候,生成了两个字符串变量 'b'. 他们的 object_id 是不一样的。而如果 a = 'b', b = a, 此时相比则返回的是 true.

==

一般意义的值比较。可以跨类使用。比如 Float 和 Fixnum 类之间的比较。 1.0 == 1 结果是 true 的。就是因为覆盖了相应的 == 方法。

===

case 里会调用该方法。假设 b = A.new , 调用 A === b, 当 a 为 Class 对象的时候,会调用 b.kind_of? a, 结果是返回 true 的,但是 b === a, 则会返回 false. 同理,当你 case b when A, 此时 when 里面的代码块也会执行,其他情况下,表现与 == 相同。

is_a?/kind_of?

检查 一个对象是否是 Class 的一个实例。Class 可以不是 对象类的父类。

instance_of

检查 一个对象是否是 Class 的一个实例。Class 不可以是 对象类的父类。比如 a.instance_of B 可以翻译为 a.class == B

具体如下

1 === 1.0   # true
1 == 1.0    # true
1.eql?(1.0) # false

case 'string'
when String
  p 'ok'
end
# ok

case String 
when 'string'
  p 'ok'
else
  p false
end
# false 

String === 'string' # true 
'string'.kind_of?(String) # true
'string' === String # false 
5.class # Fixnum
5.kind_of?(Integer) # true
5.instance_of(Integer) # false

================ 扩展============

nil?

只有 nil 的时候会返回 true.

empty?

nil 调用会报错,检查一个对象为空。字符串,数组,hash 会检查 length 是否等于 0.

blank?

rails 的方法,相当于 nil? || empty?(这是错误的) .blank? 还会在前者的基础上检查 字符串是否为空白,空格,tab, 换行 都是空白。 ruby 中,单引号定义的 字符串不会转义,双引号定义的字符串会转义。 所以 '\n'.blank? 为 false, "\n".blank? 为 true

present?

rails 的方法,相当于 !blank?

a = nil # if 时为 false

b = ''
c = ' '

d = []
e = {}

f = false # if 时为 false
g = true

h = [nil]
i = {temp: nil}

j = 0
k = 5

a.nil? # true
b.nil? # false
c.nil? # false
d.nil? # false
e.nil? # false 
f.nil? # false 
g.nil? # false 
h.nil? # false 
i.nil? # false 
j.nil? # false 
k.nil? # false 

a.empty? # undefined method
b.empty? # true
c.empty? # false
d.empty? # true
e.empty? # true
f.empty? # undefined method
g.empty? # undefined method
h.empty? # false 
i.empty? # false 
j.empty? # undefined method 
k.empty? # undefined method

# only used in rails 
a.blank? # true
b.blank? # true
c.blank? # true
d.blank? # true
e.blank? # true
f.blank? # true 
g.blank? # false 
h.blank? # false 
i.blank? # false 
j.blank? # false 
k.blank? # false 

# only used in rails 
a.present? # false
b.present? # false
c.present? # false
d.present? # false
e.present? # false
f.present? # false 
g.present? # true 
h.present? # true 
i.present? # true 
j.present? # true 
k.present? # true 

=== is amazing

光一个比较函数就这么麻烦,感觉这才是制约 ruby 发展壮大的因素吧,太复杂。。

case 还可以匹配正则

#2 楼 @xiaoping_rubyist 复杂么?js 才叫复杂且混乱吧

#2 楼 @xiaoping_rubyist 呃,这也算复杂啊 那么你一定没写过 php

另外还有一个很腻害的,就是传说中的宇宙飞船 <=>

再另外,一说到 === 就提 case…when 其实埋没了它的实用价值,我一直用它来做正则检测,感觉比 =~ 用起来舒服

#6 楼 @jasl 😂 没写过 js。正准备学呢。

为什么会这样?

#8 楼 @w7938940 equal? 是比较两个对象是否相同。 因为数字是立即值,所以无论赋值多少次都一样。字符串每次都是新的。

#8 楼 @w7938940 查看 a 和 b 的 object_id: a.object_id b.object_id, 后两个 a 和 b 的 object_id 是不一样的。

blank 和 empty 可以简单理解为“空白的”和“空的”,比如含有一个空格的字符串" "是空白的 (blank),但它不是空的 (empty)

比较函数==,===,equal?,eql?本身有自己的基础定义,但继承它们的子类会重写某些方法,stackoverflow 上的解答说的很清楚有空看看吧 https://stackoverflow.com/questions/7156955/whats-the-difference-between-equal-eql-and

需要 登录 后方可回复, 如果你还没有账号请 注册新账号