「Ruby」Case Equality


前言

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


文章作者: Hyggge
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hyggge !
  目录