为什么switch语句执行与if语句不同的相等性测试?

时间:2011-11-14 19:45:59

标签: ruby if-statement switch-statement

为什么if语句在下面的示例中起作用,而switch statement则没有。

  • 工作:

    if ''.class == String
      puts "yep, that's a string"
    end
    
  • 不工作:

    case ''.class
    when String
      puts "yep, that's a string, but this case is never triggered"
    end
    

在上面的简单示例中,switch语句过度,但显然有一种情况是switch语句比DRyer链接elsif

4 个答案:

答案 0 :(得分:11)

实际上,ruby的“案例”与===

进行比较

所以你的例子相当于:

if ''.class === String
   puts "yep, that's a string"
end

答案 1 :(得分:5)

快速简单的答案是案例使用===(3等于)而不是2。

$ irb                                                                 
if ''.class == String
  puts "yep, that's a string"   
end 
  是的,那是一个字符串

=> nil

if ''.class === String
  puts "yep, that's a string"
end
=> nil

答案 2 :(得分:5)

这是因为case语句不使用==运算符,它使用===运算符(有时称为case equality运算符)。这取决于操作员左侧的内容。所以,如果你要像这样改变案例陈述:

case "Some string"
when String
  puts "It's a string!"
else
  puts "It's not a string!"
end

进入if语句,它将成为:

if String === "Some string"
  puts "It's a string!"
else
  puts "It's not a string!"
end

请注意,Ruby会根据您的预期执行向后,它会String === "Some string"。这是因为您真正想要做的是在此处拨打Class#===,而不是String#===。 ===运算符对任何对象的作用都取决于类。在Class#===的情况下,它大致相当于调用"Some string".is_a?(String)。但是,如果您要执行"a" === "b",则String#===方法大致相当于String#==

可以让人感到困惑,但运营商的使用很大程度上是惯用的。换句话说,“when语句中的类对象”惯用语意味着测试case对象是否属于该类。我写了一篇关于此的文章,它解释了一下,你可以阅读它here

答案 3 :(得分:3)

正如其他人所说的,Ruby中的case相等的工作方式与您预期的有所不同,所以您可以这样做

case foo
when String # that is, when String === foo, more or less when foo.class == String
  do something
end

但一般来说,你不应该。如果您明确地测试类名,那么(通常)您的OO设计存在缺陷 - 在大多数情况下,您应该尝试使用多态。换句话说,而不是

if x.class == String
  x.process_string
else
  x.process_non_string
end

您应该只有x.process,然后为process和其他类定义String。更清晰,更少的代码,不会强制调用者知道被调用对象的类。