2217

如何switch在 Ruby 中编写语句?

4

27 回答 27

2859

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 === xx === 1..5

这允许使用when如上所示的复杂子句。范围、类和各种各样的东西都可以被测试,而不仅仅是相等。

switch许多其他语言中的语句不同,Rubycase没有贯穿的语句,因此不需要以.when结尾break。您还可以在单when​​个子句中指定多个匹配项,例如when "foo", "bar".

于 2009-06-04T01:22:57.180 回答
475

case...when处理类时行为有点出乎意料。这是因为它使用了===运算符。

该运算符按预期使用文字,但不适用于类:

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

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

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

简而言之,可以通过删除.classfrom来修复上面的代码case obj.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

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

于 2011-04-17T15:20:14.847 回答
237

它是case在 Ruby 中使用的。另请参阅Wikipedia 上的“ Switch statement ”。

引:

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 上的The Ruby Programming Language(第 1 版,O'Reilly)的第 123 页左右,它说子句then后面的关键字when可以替换为换行符或分号(就像在if then else语法中一样)。(Ruby 1.8 也允许用冒号代替then,但 Ruby 1.9 不再允许这种语法。)

于 2009-06-04T01:20:35.813 回答
113

案例...当

要为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 语句”。

于 2012-07-05T13:19:42.310 回答
81

在 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

(示例取自“ 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

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

于 2013-08-01T00:04:53.747 回答
80

许多编程语言,尤其是从 C 派生的那些,都支持所谓的Switch Fallthrough。我正在寻找在 Ruby 中做同样事情的最佳方法,并认为它可能对其他人有用:

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

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

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

于 2013-12-07T12:11:35.870 回答
53

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

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

Rubycase将为此使用相等操作数===(感谢@JimDeville)。更多信息请参见“ Ruby Operators ”。这也可以使用@mmdemirbas 示例(不带参数)来完成,只有这种方法对于这些类型的情况更清洁。

于 2012-10-16T12:17:41.390 回答
37

它被称为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
于 2016-02-05T20:40:16.493 回答
33

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

因此,在case语句中,a,等价||于在if语句中。

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

请参阅“ Ruby Case 语句的工作原理以及您可以使用它做什么”。

于 2014-07-03T06:46:12.123 回答
25

Ruby 使用case来编写 switch 语句。

根据case文档:

Case 语句由一个可选条件(位于 的参数位置case)和零个或多个when子句组成。匹配条件的第一个when子句(如果条件为空,则评估为布尔真值)“获胜”,并执行其代码节。case 语句的值是successwhen子句的值,或者nil如果没有这样的子句。

case 语句可以以else子句结尾。每个whena 语句可以有多个候选值,以逗号分隔。

例子:

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

正如“ Ruby 的 case 语句 - 高级技术”所描述的 Ruby一样case

可以与Ranges一起使用:

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

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

可以与正则表达式一起使用:

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

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

可以与Procs 和 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
于 2016-07-18T19:59:10.573 回答
22

Depending on your case, you could prefer to use a hash of methods.

If there is a long list of whens and each of them has a concrete value to compare with (not an interval), it will be more effective to declare a hash of methods and then to call the relevant method from the hash like that.

# 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])
于 2014-09-18T14:48:15.287 回答
21

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

puts case a
     when 0
        "It's zero"
     when 1
        "It's one"
     end
于 2013-11-05T07:29:51.127 回答
20

多值时和无值情况:

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

这里有一个正则表达式解决方案:

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
于 2014-01-20T11:45:28.337 回答
14

case您可以在 Ruby 中以两种不同的方式编写表达式:

  1. 类似于一系列if语句
  2. 在 旁边指定一个目标,case并且每个when子句都与目标进行比较。
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
于 2017-02-16T09:32:15.767 回答
11

You can do like this in more natural way,

case expression
when condtion1
   function
when condition2
   function
else
   function
end
于 2016-05-26T09:15:12.577 回答
9

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

Ruby Equality And Object Comparison ”是关于这个话题的一个很好的讨论。

于 2013-08-06T20:18:37.090 回答
8

正如上述许多答案中所述,===运算符在case/when语句的幕后使用。

以下是有关该运算符的附加信息:

大小写相等运算符:===

许多 Ruby 的内置类,例如 String、Range 和 Regexp,都提供了它们自己的===运算符实现,也称为“大小写相等”、“三等号”或“三等号”。因为它在每个类中的实现方式不同,所以它的行为会根据它被调用的对象类型而有所不同。通常,如果右侧的对象“属于”或“是”左侧的对象,则返回 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。换句话说,左侧操作数的类将定义===将调用该方法的哪个实现,因此操作数位置不可互换。

正则表达式的实现===

如果右侧的字符串与左侧的正则表达式匹配,则返回 true。

/zen/ === "practice zazen today"  # Output: => true
# is similar to
"practice zazen today"=~ /zen/

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

于 2016-07-06T16:07:17.373 回答
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
于 2016-03-12T06:33:17.583 回答
4

我已经开始使用:

a = "secondcase"

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

puts var_name
>> "bar"

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

于 2014-07-07T21:18:24.903 回答
4
$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

有关更多信息,请参阅“ Ruby - if...else, case, unless ”。

于 2017-11-13T07:58:42.167 回答
3

在您的环境中不支持正则表达式?例如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在类方法语句中使用了 s,因为||它的优先级高于 .include?.

如果您仍然喜欢使用||即使or在这种情况下更可取,您也可以这样做(item.include? 'A') || ...:你可以在这个repl.it中测试它。

于 2018-04-18T11:29:29.163 回答
3

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

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,所以你可以使用你喜欢的。

在 Ruby 2.6 之后您可以使用Endless Ranges在 Ruby 2.7 之后您还可以使用Beginless Ranges,因此您可以这样做:

case x
when 1..5
  "It's between 1 and 5"
when 6
  "It's 6"
when (7..)
  "It's equal or greater than 7"
when (..0)
  "It's equal or less than 0"
end
于 2021-04-29T09:25:02.983 回答
3

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

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

x不小于 2,但返回值为"apple". 为什么?因为x是 3 并且因为',`` acts as an|| , it did not bother to evaluate the expressionx < 2'。

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

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

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

要进行&&比较,您必须caseif/else块一样对待:

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

在 Ruby Programming Language 书中,Matz 说后一种形式是简单(且不经常使用)的形式,它只不过是if/ elsif/的另一种语法else。但是,无论它是否不经常使用,我都看不到任何其他方法可以为给定子句附加多个&&表达式。when

于 2019-03-20T20:16:13.740 回答
2

case语句运算符switch与其他语言中的一样。

这是switch...caseC 中的语法:

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

这是case...whenRuby 中的语法:

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文档。

于 2019-11-01T13:35:22.473 回答
1

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

例如,

x = 22

CASE x
  WHEN 0..14 THEN puts "#{x} is less than 15"    
  WHEN 15 THEN puts "#{x} equals 15" 
  WHEN 15 THEN puts "#{x} equals 15" 
  WHEN 15..20 THEN puts "#{x} is greater than 15" 
  ELSE puts "Not in the range, value #{x} " 
END
于 2019-01-25T07:32:41.587 回答
1

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
于 2021-07-22T23:42:52.067 回答
0

我更喜欢用 case + 而不是

number = 10

case number
when 1...8 then # ...
when 8...15 then # ...
when 15.. then # ...
end
于 2021-02-17T19:00:03.047 回答