前言
当笔者第一次看到===
时,便想当然的认为这与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