如何在Ruby中编写switch语句?


当前回答

在when子句中强调逗号(,)至关重要。它充当if语句的||,也就是说,它在when子句的分隔表达式之间进行OR比较,而不是and比较。参见以下案例陈述:

x = 3
case x
  when 3, x < 2 then 'apple'
  when 3, x > 2 then 'orange'
end
 => "apple"

x不小于2,但返回值为“apple”。为什么?因为x是3,并且由于“,”充当||,所以它不必计算表达式x<2。

您可能认为,要执行AND,可以执行以下操作,但它不起作用:

case x
  when (3 && x < 2) then 'apple'
  when (3 && x > 2) then 'orange'
end
 => nil 

它不起作用,因为(3&&x>2)的计算结果为true,Ruby获取true值,并将其与x进行比较,使用==,这是不正确的,因为x是3。

要进行&&比较,您必须将case视为if/else块:

case
  when x == 3 && x < 2 then 'apple'
  when x == 3 && x > 2 then 'orange'
end

在《Ruby编程语言》一书中,Matz表示后一种形式是简单的(而且很少使用)形式,它只是if/elsif/else的一种替代语法。然而,无论它是否不经常使用,我看不到任何其他方法可以为给定的when子句附加多个&&表达式。

其他回答

许多编程语言,特别是源于C的语言,都支持所谓的Switch Fallthrough。我正在寻找在Ruby中实现这一点的最佳方法,并认为这可能对其他人有用:

在类C语言中,故障通常如下所示:

switch (expression) {
    case 'a':
    case 'b':
    case 'c':
        // Do something for a, b or c
        break;
    case 'd':
    case 'e':
        // Do something else for d or e
        break;
}

在Ruby中,同样可以通过以下方式实现:

case expression
when 'a', 'b', 'c'
  # Do something for a, b or c
when 'd', 'e'
  # Do something else for d or e
end

这并不是严格等价的,因为不可能让“a”在变成“b”或“c”之前执行一块代码,但在大多数情况下,我发现它足够相似,以同样的方式有用。

这是在Ruby中使用case完成的。另请参阅维基百科上的“Switch语句”。

引用:

case n
when 0
  puts 'You typed zero'
when 1, 9
  puts 'n is a perfect square'
when 2
  puts 'n is a prime number'
  puts 'n is an even number'
when 3, 5, 7
  puts 'n is a prime number'
when 4, 6, 8
  puts 'n is an even number'
else
  puts 'Only single-digit numbers are allowed'
end

另一个例子:

score = 70

result = case score
   when 0..40 then "Fail"
   when 41..60 then "Pass"
   when 61..70 then "Pass with Merit"
   when 71..100 then "Pass with Distinction"
   else "Invalid Score"
end

puts result

在我的Kindle上的《Ruby编程语言》(第一版,O'Reilly)第123页左右,它说when子句后面的then关键字可以用换行符或分号替换(就像if-then-else语法中的那样)。(Ruby 1.8也允许用冒号代替then,但Ruby 1.9中不再允许使用这种语法。)

Ruby在2.7中引入了模式匹配

这是一个超级强大的功能

它也使用case,但有另一种语法

还有查找模式功能

users =
  { users:
    [
      { user: 'user', email: 'user@user.com' },
      { user: 'admin', email: 'admin@admin.com' },
    ]
  }

case users
in users: [*, { user:, email: /admin/ => admin_email }, *]
  puts admin_email
else
  puts "No admin"
end

# will print admin@admin.com

与通常情况不同,如果条件不匹配,将抛出NoMatchingPatternError。所以你可能不得不使用else分支

我已经开始使用:

a = "secondcase"

var_name = case a
  when "firstcase" then "foo"
  when "secondcase" then "bar"
end

puts var_name
>> "bar"

在某些情况下,它有助于压缩代码。

由于switch-case始终返回单个对象,因此我们可以直接打印其结果:

puts case a
     when 0
        "It's zero"
     when 1
        "It's one"
     end