如何在 Ruby 中编写 switch 语句

如何在 Ruby 中编写switch语句?

答案

Ruby 使用case表达式代替。

case x
when 1..5
  "It's between 1 and 5"
when 6
  "It's 6"
when "foo", "bar"
  "It's either foo or bar"
when String
  "You passed a string"
else
  "You gave me #{x} -- I have no idea what to do with that."
end

Ruby 使用===运算符将when子句中的对象与case子句中的对象进行比较。例如, 1..5 === x ,而不是x === 1..5

如上所述,这可以实现复杂的when子句。可以测试范围,类和各种各样的东西,而不仅仅是相等性。

不像switch在许多其他语言的语句,Ruby 的case并没有落空 ,所以没有必要每次结束whenbreak 。您还可以在单个when子句中指定多个匹配项,例如when "foo", "bar"

case...when处理类case...when表现异常。这是由于它使用===运算符。

该运算符可以按预期使用文字,但不能使用类:

1 === 1           # => true
Fixnum === Fixnum # => false

这意味着,如果您想做一个case ... when在对象的类上时,这将不起作用:

obj = 'hello'
case obj.class
when String
  print('It is a string')
when Fixnum
  print('It is a number')
else
  print('It is not a string or number')
end

将打印 “不是字符串或数字”。

幸运的是,这很容易解决。已定义===运算符,以便在将其与一个类一起使用并提供该类的实例作为第二个操作数时返回true

Fixnum === 1 # => true

简而言之,可以通过删除.class来修复以上代码:

obj = 'hello'
case obj  # was case obj.class
when String
  print('It is a string')
when Fixnum
  print('It is a number')
else
  print('It is not a string or number')
end

我今天在寻找答案时遇到了这个问题,这是第一个出现的页面,因此我认为它对处于相同情况的其他人很有用。

这是通过在 Ruby 中使用case来完成的。另请参阅 Wikipedia 上的 “ 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 编程语言 (第 1 版,O'Reilly)》的第 123 页左右,它说when子句后面的then关键字可以用换行符或分号代替(就像if then else语法一样)。 (Ruby 1.8 还允许使用冒号代替then ,但是 Ruby 1.9 中不再允许使用此语法。)

案例... 当

Chuck 的答案中添加更多示例:

带参数:

case a
when 1
  puts "Single value"
when 2, 3
  puts "One of comma-separated values"
when 4..6
  puts "One of 4, 5, 6"
when 7...9
  puts "One of 7, 8, but not 9"
else
  puts "Any other thing"
end

没有参数:

case
when b < 3
  puts "Little than 3"
when b == 3
  puts "Equal to 3"
when (1..10) === b
  puts "Something in closed range of [1..10]"
end

请注意 kikito 警告的 “ 如何在 Ruby 中编写 switch 语句 ”。

许多编程语言(尤其是从 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 2.0 中,您还可以在case语句中使用 lambda,如下所示:

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

(示例摘自 “ procs 是否可以与 Ruby 2.0 中的 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 语句如何工作以及您可以如何使用它 ”。)

您可以使用正则表达式,例如查找字符串类型:

case foo
when /^(true|false)$/
   puts "Given string is boolean"
when /^[0-9]+$/ 
   puts "Given string is integer"
when /^[0-9\.]+$/
   puts "Given string is float"
else
   puts "Given string is probably string"
end

Ruby 的case将为此使用等于操作数=== (感谢 @JimDeville)。其他信息可在 “ Ruby 运算符 ” 中获得。也可以使用 @mmdemirbas 示例(不带参数)完成此操作,只有这种方法对于此类情况更干净。

如果您想知道如何在 Ruby 转换案例中使用 OR 条件:

所以,在一个case声明,一,是相当于||if语句中。

case car
   when 'Maruti', 'Hyundai'
      # Code here
end

请参阅 “ Ruby Case 语句如何工作以及如何使用它 ”。

这就是所谓的case ,它的工作原理与您预期的一样,外加===更多有趣内容,它们实现了测试。

case 5
  when 5
    puts 'yes'
  else
    puts 'else'
end

现在找点乐子:

case 5 # every selector below would fire (if first)
  when 3..7    # OK, this is nice
  when 3,4,5,6 # also nice
  when Fixnum  # or
  when Integer # or
  when Numeric # or
  when Comparable # (?!) or
  when Object  # (duhh) or
  when Kernel  # (?!) or
  when BasicObject # (enough already)
    ...
end

事实证明,您还可以通过省略初始case参数并只编写第一个匹配项的表达式来替换case的任意 if / else 链(即,即使测试不涉及公共变量)想。

case
  when x.nil?
    ...
  when (x.match /'^fn'/)
    ...
  when (x.include? 'substring')
    ...
  when x.gsub('o', 'z') == 'fnzrq'
    ...
  when Time.now.tuesday?
    ...
end

根据您的情况,您可能更喜欢使用方法的哈希。

如果有一个长的列表when S 和他们每个人都有一个具体的数值与(不是间隔)进行比较,这将是更有效的申报方法的哈希,然后调用从这样的散列的相关方法。

# Define the hash
menu = {a: :menu1, b: :menu2, c: :menu2, d: :menu3}

# Define the methods
def menu1
  puts 'menu 1'
end

def menu2
  puts 'menu 2'
end

def menu3
  puts 'menu3'
end

# Let's say we case by selected_menu = :a
selected_menu = :a

# Then just call the relevant method from the hash
send(menu[selected_menu])