如何在Ruby中编写switch语句

时间:2009-06-04 01:18:01

标签: ruby switch-statement conditional

如何在Ruby中编写switch语句?

27 个答案:

答案 0 :(得分:2493)

Ruby使用case expression代替。

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没有fall-through,因此无需使用when结束每个break 。您还可以在单​​个when子句中指定多个匹配项,例如when "foo", "bar"

答案 1 :(得分:419)

处理类时,

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')
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')
end

我今天在寻找答案时遇到了这个问题,这是第一个出现的页面,所以我认为在同样的情况下对其他人有用。

答案 2 :(得分:199)

由Ruby中的case完成。另请参阅this article on Wikipedia

引用:

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

The Ruby Programming Lanugage (第1版,O'Reilly)的第123页(我正在使用Kindle)上,它在then之后显示when关键字子句可以用换行符或分号替换(就像在if then else语法中一样)。 (Ruby 1.8也允许使用冒号代替then ......但Ruby 1.9中不再允许使用这种语法。)

答案 3 :(得分:91)

案例......何时

Chuck's answer添加更多示例:

使用参数:

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警告的the issue

答案 4 :(得分:69)

许多编程语言,特别是那些源自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'执行代码块,但在大多数情况下我发现它类似足以以同样的方式有用。

答案 5 :(得分:66)

在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

(取自“Can procs be used with case statements in Ruby 2.0?”的例子。)

或者,完整的课程:

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

(取自“How A Ruby Case Statement Works And What You Can Do With It”的例子。)

答案 6 :(得分:50)

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

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 Operators”。这也可以使用@mmdemirbas示例(不带参数)来完成,只有这种方法对于这些类型的情况更清晰。

答案 7 :(得分:30)

如果您渴望知道如何在Ruby switch案例中使用OR条件:

因此,在case声明中,,相当于||声明中的if

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

Many other things you can do with a Ruby case statement

答案 8 :(得分:29)

它被称为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

答案 9 :(得分:20)

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

如果有一个很长的时间列表,并且每个都有一个具体值要与之比较(不是间隔),那么声明方法的散列然后从散列调用相关方法会更有效这一点。

# 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])

答案 10 :(得分:20)

Ruby使用case来编写switch语句。

根据Ruby Docs

  

案例陈述包含一个可选条件,该条件位于   参数的位置为case,以及零个或多个when个子句。   第一个when子句匹配条件(或评估为   布尔值,如果条件为null)“wins”及其代码节   被执行。 case语句的值是。的值   成功的when子句,如果没有这样的子句,则为nil

     

case语句可以以else子句结束。每个when a   语句可以有多个候选值,用逗号分隔。

示例:

case x
when 1,2,3
  puts "1, 2, or 3"
when 10
  puts "10"
else
  puts "Some other number"
end

更短的版本:

case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then puts "10"
else puts "Some other number"
end

正如Honeybadger的博客描述Ruby Case;

可与Ranges一起使用:

case 5
when (1..10)
  puts "case statements match inclusion in a range"
end

## => "case statements match inclusion in a range"

可与Regex一起使用:

case "FOOBAR"
when /BAR$/
  puts "they can match regular expressions!"
end

## => "they can match regular expressions!"

可与Procs and Lambdas一起使用:

case 40
when -> (n) { n.to_s == "40" }
  puts "lambdas!"
end

## => "lambdas"

此外,可以与您自己的匹配类一起使用:

class Success
  def self.===(item)
    item.status >= 200 && item.status < 300
  end
end

class Empty
  def self.===(item)
    item.response_size == 0
  end
end

case http_response
when Empty
  puts "response was empty"
when Success
  puts "response was a success"
end

答案 11 :(得分:19)

由于switch case总是返回单个对象,我们可以直接打印其结果:

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

答案 12 :(得分:18)

多值时无值情况:

print "Enter your grade: "
grade = gets.chomp
case grade
when "A", "B"
  puts 'You pretty smart!'
when "C", "D"
  puts 'You pretty dumb!!'
else
  puts "You can't even use a computer!"
end

这里有一个regular expression解决方案:

print "Enter a string: "
some_string = gets.chomp
case
when some_string.match(/\d/)
  puts 'String has numbers'
when some_string.match(/[a-zA-Z]/)
  puts 'String has letters'
else
  puts 'String has no numbers or letters'
end

答案 13 :(得分:11)

您可以在ruby中以两种不同的方式编写案例表达式。

  1. 类似于一系列&#34; if&#34;语句
  2. 指定案例旁边的目标,并且每个&#34;当&#34;将子句与目标进行比较。
  3. 第一路

    age = 20
    case 
    when age >= 21
    puts "display something"
    when 1 == 0
    puts "omg"
    else
    puts "default condition"
    end
    

    第二路

     case params[:unknown]
     when /Something/ then 'Nothing'
     when /Something else/ then 'I dont know'
     end
    

答案 14 :(得分:8)

你可以用更自然的方式做到这一点,

case expression
when condtion1
   function
when condition2
   function
else
   function
end

答案 15 :(得分:8)

很多很棒的答案,但我想我会添加一个factoid ..如果你试图比较对象(Classes),请确保你有一个太空船方法(不是一个笑话)或者理解它们是如何被比较的

以下是对该主题的一个很好的讨论 http://www.skorks.com/2009/09/ruby-equality-and-object-comparison/

答案 16 :(得分:5)

puts "Recommend me a language to learn?"
input = gets.chomp.downcase.to_s

case input
when 'ruby'
    puts "Learn Ruby"
when 'python'
    puts "Learn Python"
when 'java'
    puts "Learn Java"
when 'php'
    puts "Learn PHP"
else
    "Go to Sleep!"
end

答案 17 :(得分:5)

如上面的许多答案中所述,= case运算符在case / when语句的引擎下使用。

以下是有关该运营商的一些额外信息。

个案等值运算符:===

许多Ruby的内置类(如String,Range和Regexp)都提供了自己的===运算符实现,也称为case-equality,triple equals或threequals。因为它在每个类中的实现方式不同,所以它的行为会有所不同,具体取决于调用它的对象类型。通常,如果右侧的对象“属于”或“是左侧对象的成员”,则返回true。例如,它可用于测试对象是否是类(或其子类之一)的实例。

String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

使用其他最适合工作的方法可以达到同样的效果,例如is_a?和instance_of?。

===

的范围实施

当在范围对象上调用===运算符时,如果右边的值落在左边的范围内,则返回true。

(1..4) === 3  # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6  # Output: => false

("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false

请记住,===运算符会调用左侧对象的===方法。所以(1..4)=== 3相当于(1..4)。=== 3.换句话说,左操作数的类将定义===方法的哪个实现将是调用,因此操作数位置不可互换。

Regexp实现===

如果右侧的字符串与左侧的正则表达式匹配,则返回true。     / zen / ===“今天练习zazen”#输出:=&gt;真正     # 类似于     “今天练习zazen”=〜/ zen /

上面两个例子之间唯一相关的区别是,当匹配时,===返回true而= =返回一个整数,这是Ruby中的真值。我们很快就会回到这里。

答案 18 :(得分:3)

$age =  5
case $age
when 0 .. 2
   puts "baby"
when 3 .. 6
   puts "little child"
when 7 .. 12
   puts "child"
when 13 .. 18
   puts "youth"
else
   puts "adult"
end

reference =&gt; https://www.tutorialspoint.com/ruby/ruby_if_else.htm

答案 19 :(得分:1)

我已经开始使用:

a = "secondcase"

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

puts var_name
>> "bar"

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

答案 20 :(得分:1)

您的环境中是否不支持正则表达式?例如。 Shopify Script Editor(2018年4月):

  

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

根据herehere之前已涵盖的方法组合的解决方法:

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,因为||的优先级高于。{1}} .include?。如果您是ruby-nazi,请设想我使用此(item.include? 'A') || ...代替。 repl.it测试。

答案 21 :(得分:1)

我们可以为多个条件编写switch语句。

例如,

$total='';

答案 22 :(得分:1)

如果您需要“小于”或“大于”:

case x
when 1..5
  "It's between 1 and 5"
when 6
  "It's 6"
when 7..1.0/0
  "It's equal or greater than 7"
when -1.0/0..0
  "It's equal or less than 0"
end

1.0/0 等于 Float::INFINITY,所以你可以使用你喜欢的。

答案 23 :(得分:0)

在when子句充当||时,强调逗号','是至关重要的。 if语句的含义,即在when子句的分隔表达式之间进行“或”比较而不是“与”比较。因此,请检查以下案例声明。显然,x不小于2,但返回值为'apple'。为什么?因为x为3,并且因为','充当||,所以不必理会表达式'x <2'。

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

您可能会认为要执行AND,可以在下面执行以下操作。但这是行不通的。这是因为(3 && x> 2)的计算结果为true,而ruby取True值并将其与===进行比较,这显然是不正确的,因为x为3。

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

要进行&&比较,您必须像对待大小写一样对待,否则阻止:

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

在Ruby编程语言书中,Matz说后一种形式是简单的(并且很少使用)形式,仅是if / elsif / else的替代语法。但是,无论是否经常使用它,对于给定的“何时”子句,我都看不到任何其他方式来附加多个&&表达式。

答案 24 :(得分:0)

case语句运算符与其他语言中的switch类似。

这是switch...case在C语言中的语法:

switch (expression)
​{
    case constant1:
      // statements
      break;
    case constant2:
      // statements
      break;
    .
    .
    .
    default:
      // default statements
}

这是Ruby中case...when的语法:

case expression
  when constant1, constant2 #Each when statement can have multiple candidate values, separated by commas.
     # statements 
     next # is like continue in other languages
  when constant3
     # statements 
     exit # exit is like break in other languages
  .
  .
  .
  else
     # statements
end

例如:

x = 10
case x
when 1,2,3
  puts "1, 2, or 3"
  exit
when 10
  puts "10" # it will stop here and execute that line
  exit # then it'll exit
else
  puts "Some other number"
end

有关更多信息,请参见case文档。

答案 25 :(得分:0)

我更喜欢使用 case + 而非

number = 10

case number
when 1...8 then # ...
when 8...15 then # ...
when 15.. then # ...
end

答案 26 :(得分:0)

Ruby 支持 case 表达式。

类匹配:

case e = StandardError.new("testing")
when Exception then puts "error!"
else puts "ok!"
end # => error! 

多值匹配:

case 3
when 1,2,3 then puts "1..3"
when 4,5,6 then puts "4..6"
else puts "?"
end # => 1..3

正则表达式评估:

case "monkey"
when /mon/ then puts "banana"
else puts "?" 
end # => banana