前言
当笔者第一次看到===时,便想当然的认为这与JavaScript中===的用法相同,即“同时比较数据类型和数值”。为了验证这个猜想,我在irb中做了以下测试

1.0是浮点类型,而1是整数类型,但是1===1.0的结果却是true。很显然,我一开始的猜想是不正确的。
随后通过查阅资料得知,当比较两个相同类型的对象时,===
的用法和 ==
相同;但是在其他情况下,尤其是比较两个不同类型的对象时,===的用法会随着对象类型的不同而不同。尽管这些用法看上去眼花缭乱,但是仔细想想会发现它们有着异曲同之妙...
相同类型对象比较
当我们在比较数字、比较字符串或者比较其他大多数类型的对象时,可以将===当做==来使用——
# 比较数字
a, b = 1, 1
puts a === b # output: true
# 比较字符串
a, b = "hello", "world"
puts a === b # output: false
# 比较数组
a, b = [1, 2, 3], [1, 2, 3]
puts a == b # output: false
不过这种用法不常见,毕竟能写==为什么要大费周章地写===呢?
不同类型对象比较
当我们比较两个不同类型的对象时,===的用法便随着对象类型的不同而不同了——
当左侧是整数,右侧是浮点数,如果两数的值相等,则表达式会返回true,否则返回false (其实就是引言中的例子)。此时,
===相当于==。
1 === 1.0 # output: true 6.0 === 6 # output: true当左侧是类名,右侧是某个对象时,如果该对象是左侧的类的实例,则表达式会返回true,否则返回false。此时,
===相当于is_a?。
String === "hyggge" # output: true Range === (1..2) # output: true Array === [1, 2, 3] # output: true Integer === 2 # output: true当左侧是范围,右侧是某个值时,如果该值落在左侧的范围中, 则表达式会返回true,否则返回false。此时,
===相当于include?。
(1...5) === 2 # output: true ("a"..."g") === "c" # output: true当左侧是正则表达式,右侧是某个字符串对象时,如果该字符串能够匹配上左侧的正则表达式,则会返回true,否则返回false。此时,
===相当于=~。
/^[A-Z]*$/ === "HELLO" # output:true /[0-9]+/ === "12" # output:true
内在联系
以上各个用法看上去不尽相同,但它们之间实际上是有一定联系的。在Stack Overflow上有人这样描述[1]——
The best way to describe a === b is "if I have a drawer labeled a, does it make sense to put b in it?"
也就是说,我们可以===的左边看做一个容器,如果===右边的对象放在该容器中有意义,那么整个表达式的返回值就是true,否则就返回false。
对于两个不同的对象来说,这种判断方式是很显然的。
以String === "hyggge"为例,"hyggge"是一个字符串对象,是String类的一个实例,如果我们把===左边的String看做所有字符串对象组成的集合,"hyggge"放在这个集合中显然是有意义的,因此返回值是true。再以(1..5) === 3
为例,3是一个整数,而范围(1..5)可以看做一个集合
\(\{1,2,3,4,5\}\),很显然1在这个集合中。
对于两个相同的对象来说,这种判断方式仍然是成立的。
以[1, 2, 3] === [1, 2, 3]为例,===两边都是数组对象,但此时我们仍可以将===左边看成一个集合,只不过这个集合只有一个元素,即\(\{[1, 2, 3]\}\),
===右边的[1, 2, 3]显然也是在这个集合中的,因此返回true也就不足为奇了。
[1]参考http://stackoverflow.com/a/3422349/1772
=== 与 case/when语句
===
运算符也被用在case/when语句的底层实现中,这也是它最为常见的用途。以下面的case/when语句为例
case input
when 1 then puts "1"
when "hyggge" then puts "\"hyggge\""
when (10..20) then puts "10..20"
when Array then puts "Array"
when /regex/ then puts "/regex/"
else puts "other"
end上述代码等价于——
if 1 === input then puts "1"
elsif "hyggge" === input then puts "\"hyggge\""
elsif (10..20) === input then puts "10..20"
elsif Array === input then puts "Array"
elsif /regex/ === input then puts "/regex/"
else puts "other"
end