Ruby 分析 Ruby 中的比较函数

308820773 · 发布于 2016年12月30日 · 最后由 rennyallen 回复于 2017年1月04日 · 774 次阅读
29920

在学习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 
共收到 11 条回复
19780
torvaldsdb · #1 · 2016年12月30日

=== is amazing

96
xiaoping_rubyist · #2 · 2016年12月31日

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

8744
lithium4010 · #3 · 2016年12月31日

case 还可以匹配正则

2329
mingyuan0715 · #4 · 2016年12月31日

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

3035
IChou · #5 · 2017年1月01日

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

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

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

1107
jasl · #6 · 2017年1月01日 2 个赞
96
xiaoping_rubyist · #7 · 2017年1月01日

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

96
w7938940 · #8 · 2017年1月03日

为什么会这样?

481
messiahxu · #9 · 2017年1月03日

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

9626
yaocanwei · #10 · 2017年1月03日

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

26688
rennyallen · #11 · 2017年1月04日

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

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