Ruby Ruby 下的 ===, ==, eql?, equal?

algo31031 · 2014年05月14日 · 最后由 algo31031 回复于 2014年05月15日 · 3432 次阅读

=== case equality

严格说来,这个其实跟另外三个不属于一类。

a === b 相当于 "如果我有一个贴了 a 标签的抽屉,那么把 b 放到这个抽屉里是否可行?"

作为 case equality operator, 其首要作用自然是在when/case里,作为判断进入某个分支的依据

a = 5

case a
when Integer
  "case Integer"
when 5
  "case 5"
end

这段代码其实是会返回"case Integer"的,因为

2.1.1 :043 > Integer === 5
 => true 

相应的

2.1.1 :054 > (1..5) === 5
 => true 
2.1.1 :055 > (1...5) === 5
 => false 
2.1.1 :058 > /(a|e|i|o|u)/ === "hello"
 => true  

对于Object#===, 事实上等价于Object#==.
但是对 Object 的子类,===一般会被重写,使其在条件表达式里有意义。

==

==是最为常用的用于比较两个对象值是否相等的方法

a == b相当于判断"a 的值与 b 的值相同吗"

==方法经常被 Object 子类重写以满足其自身需求

equal?

equal?方法用来判断 2 个对象是否是同一个对象

a.equal? b相当于判断"a 就是 b 吗"

2.1.1 :005 > "a" == "a"
 => true 
2.1.1 :006 > "a".equal? "a"
 => false 
2.1.1 :007 > :a.equal? :a
 => true 

==不同,equal?不应该被子类重写

eql?

==类似,但是可以看做是更严格的==
Object里,==eql?是同意,但是很多子类会重写eql?以提供更严格的比较,比如:

2.1.1 :010 > 1 == 1
 => true 
2.1.1 :011 > 1 == 1.0
 => true 
2.1.1 :012 > 1.eql? 1.0
 => false 

=== 没有看懂 a === b 相当于 "如果我有一个贴了a标签的抽屉, 那么把b放到这个抽屉里是否可行?"

我以为是类似 include?的作用,发现不是

那么什么时候会用到这种东西,有实际代码么?

别的语言的===是恒等于的意思 比如

false == 0 == nil
false !=== 0 !=== nil

看来在 ruby 我果断用错了

#1 楼 @palytoxin ===作用是不太好说明白,一开始是想说成“a 定义了一个范围然后判断 b 是否在这个范围之内”,但是这么很容易就让人联想到了include? 进一步说, Integer === 5可以返回 true,因为 5 在 Integer 的范围(抽屉)里,但是5 === Integer显然是不行的

至于作用,最主要的就是上面说的,在自己的类里面重写===,让 case/when 条件表达式根据自己的类的业务,有个判断 case 后面的值该进入哪个分支的依据

比如这里, Regexp 重写了===方法,于是 when 后面可以放正则表达式

#3 楼 @algo31031 去 stackoverflow 翻了下,那种 case-when 的方法我不太好理解。。。 我自己理解上 === 和 is_a?/ kind_of? 是不是更类似? 5.is_a? Integer #=> true Symbol === :yes #=> true 还发现一个好用的方法

divisible_by_three = ->(x){x % 3 == 0}
divisible_by_three === 42 # => true

#4 楼 @palytoxin

case/when那里如果不好理解, 可以拿<=>方法做个类比

比如我们自己定义了个User类,如果直接就User.all.sort, 是不可以的, 如果想这么用,你就需要首先在 User 里面定义一个 <=>方法用于比较 2 个 user 对象

稍微有点不同的是,因为===是定义在 Object 里的,所以即便对自己定义的类里面不重写===方法,一样可以对其使用 case/when. 但是这样会调用Object#===, 可能不会得到自定义类需要达到的效果。

依然用我顶楼===里的那个例子来说 如果 Integer 里面没有重写===方法,那么得到的返回值就不再是"case Integer",而是"case 5"了

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