如何在Ruby中编写switch语句?


当前回答

在Ruby 2.0中,您还可以在case语句中使用lambdas,如下所示:

is_even = ->(x) { x % 2 == 0 }

case number
when 0 then puts 'zero'
when is_even then puts 'even'
else puts 'odd'
end

您还可以使用Struct和自定义===

Moddable = Struct.new(:n) do
  def ===(numeric)
    numeric % n == 0
  end
end

mod4 = Moddable.new(4)
mod3 = Moddable.new(3)

case number
when mod4 then puts 'multiple of 4'
when mod3 then puts 'multiple of 3'
end

(示例取自“在Ruby 2.0中,procs可以与case语句一起使用吗?”。)

或者,对于完整的类:

class Vehicle
  def ===(another_vehicle)
    self.number_of_wheels == another_vehicle.number_of_wheels
  end
end

four_wheeler = Vehicle.new 4
two_wheeler = Vehicle.new 2

case vehicle
when two_wheeler
  puts 'two wheeler'
when four_wheeler
  puts 'four wheeler'
end

(示例摘自“Ruby Case语句的工作原理和使用它可以做什么”。)

其他回答

很多很好的答案,但我想我会补充一个事实。。如果您试图比较对象(类),请确保您有一个太空船方法(不是玩笑)或了解它们是如何比较的

“Ruby平等和对象比较”是一个很好的话题讨论。

这是在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分支

在您的环境中不支持正则表达式?例如,Shopify脚本编辑器(2018年4月):

[错误]:未初始化常量RegExp

一种变通方法,结合了前面在这里和这里介绍过的方法:

code = '!ADD-SUPER-BONUS!'

class StrContains
  def self.===(item)
    item.include? 'SUPER' or item.include? 'MEGA' or\
    item.include? 'MINI' or item.include? 'UBER'
  end
end

case code.upcase
when '12345PROMO', 'CODE-007', StrContains
  puts "Code #{code} is a discount code!"
when '!ADD-BONUS!'
  puts 'This is a bonus code!'
else
  puts 'Sorry, we can\'t do anything with the code you added...'
end

我在类方法语句中使用了or,因为||的优先级高于包括

如果您仍然喜欢使用||,即使在这种情况下或更可取,也可以改为使用:(item.include?“A”)||。。。。您可以在这个repl.it中测试它。

在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子句附加多个&&表达式。