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

发布于 2024-12-16 10:52:33 字数 406 浏览 2 评论 0原文

为什么 if 语句在下面的示例中有效,而 switch 语句 没有。

  • 工作:

    if ''.class == 字符串
      放“是的,那是一个字符串”
    结尾
    
  • 不工作:

    case ''.class
    当字符串
      提出“是的,这是一个字符串,但这种情况永远不会触发”
    结尾
    

在上面的简单示例中,switch 语句有点过分了,但显然在某些情况下 switch 语句比链接的 elsif 更干燥

Why does the if statement work in the example below while the switch statement does not.

  • working:

    if ''.class == String
      puts "yep, that's a string"
    end
    
  • not working:

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

In the trivial example above, the switch statement is overkill, but there are obviously situations where a switch statement would be DRYer than chained elsifs

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

早乙女 2024-12-23 10:52:33

实际上,ruby 的“case”与 === 进行比较,

因此您的示例相当于:

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

Actually, ruby's "case" makes the comparaison with ===

So your example is equivalent to :

if ''.class === String
   puts "yep, that's a string"
end
指尖上的星空 2024-12-23 10:52:33

这是因为 case 语句不使用 == 运算符,而是使用 === 运算符(有时称为 case 相等运算符)。其作用取决于操作符左侧的内容。因此,如果您将这样的 case 语句转换

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 == =“一些字符串”。这是因为您真正想要做的是在这里调用 Class#===,而不是 String#===。 === 运算符对任何对象的作用实际上取决于类。对于Class#===,它大致相当于调用"Some string".is_a?(String)。但如果您要执行 "a" === "b",则 String#=== 方法大致相当于 String#==.

可能会令人困惑,但操作符的用法很大程度上是惯用的。换句话说,“when 语句中的类对象”习惯用法意味着测试 case 对象是否属于该类。我写了一篇对此进行了更多解释的文章,您可以阅读它 这里

This is because the case statement doesn't use the == operator, it uses the === operator (sometimes called the case equality operator). What this does varies depending on what's on the left side of the operator. So, if you were to transform case statement like this:

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

Into an if statement, it would become this:

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

Note that Ruby does this backwards from how you'd expect, it does String === "Some string". This is because what you really want to do is call Class#=== here, and not String#===. What the === operator does for any object is really up to the class. In the case of Class#===, it's roughly equivalent to calling "Some string".is_a?(String). But if you were to do "a" === "b", the String#=== method is roughly equivalent to String#==.

It can get confusing, but the operator's usage is largely idiomatic. In other words, the "class object in a when statement" idiom means to test if the case object is of that class. I've written an article on this that explains it a bit more, you can read it here.

你与昨日 2024-12-23 10:52:33

快速而简单的答案是 case 使用 === (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

The quick and simple answer is that case uses === (3 equals) and not two.

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

yep, that's a string

=> nil

if ''.class === String
  puts "yep, that's a string"
end
=> nil
飘然心甜 2024-12-23 10:52:33

正如其他人所说,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,然后为 String 和其他类定义不同的 process。更干净、更少的代码,不会强迫调用者知道被调用对象的类。

As others have said, case equality in Ruby works a bit differently than you might expect, so you can just do

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

But generally, you shouldn't. If you're explicitly testing class names, then (usually) your OO design is flawed -- in most cases, you should try to use polymorphism instead. In other words, instead of

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

you should simply have x.process, and then define process differently for String and other classes. Cleaner, less code, doesn't force the caller to know the class of the called object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文