ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Ruby 中编写 switch 语句

如何在 Ruby 中编写 switch 语句?


D
DTavaszi

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,因此无需以 break 结束每个 when。您还可以在单个 when 子句(如 when "foo", "bar")中指定多个匹配项。


您还可以对传递的参数执行正则表达式:当 /thisisregex/ 下一行放置“This is the found match nr.1 #{$1}” end
另外值得注意的是,您可以通过将 whenreturn 语句放在同一行来缩短代码:when "foo" then "bar"
重要提示:与许多其他语言中的 switch 语句不同,Ruby 的 case 没有 fall-through,因此无需以 break 结束每个 when
这么多的赞成票甚至没有提到关键字then。另请参阅其他答案。
k
kikito

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

简而言之,可以通过从 case obj.class 中删除 .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

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


obj='你好';案例 obj;当“你好”然后把“这是你好”结束
.class 部分值得注意,谢谢。当然,这是完全合适的行为(尽管我可以看到认为会打印 It is a string 可能是一个常见错误)...您正在测试某个任意对象的 class,而不是对象本身。因此,例如:case 'hello'.class when String then "String!" when Class then "Class!" else "Something else" end 导致:"Class!" 这对于 1.class{}.class 等同样适用。删除 .class,我们会为这些不同的值得到 "String!""Something else"
谢谢你!这比我使用“case obj.class.to_s”的解决方案更优雅
n
nonopolarity

它是使用 Ruby 中的 case 完成的。另请参阅 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 页左右,它说 when 子句后面的 then 关键字可以替换为换行符或分号 (就像在 if then else 语法中一样)。 (Ruby 1.8 还允许使用冒号代替 then,但 Ruby 1.9 中不再允许使用这种语法。)


when (-1.0/0.0)..-1 then "Epic fail"
这是我使用的答案,因为我正在根据案例切换的结果定义一个变量。我可以简单地复制您所做的,而不是每行都说 type = #{score}。更优雅我也更喜欢单线(如果可能的话)
我非常喜欢 ruby,因为它让我只在这样的变量上放一个 switch 语句,减少混乱并且直截了当:D
t
the Tin Man

案例...当

要向 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 警告的“How to write a switch statement in Ruby”。


谢谢,这有助于在一行上有多个选项。我一直在尝试使用 or
C
Community

在 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

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


R
Robert Kajic

许多编程语言,尤其是从 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

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


Fallthrough 与其说是功能,不如说是一个问题。如果 Ruby 支持对 fallthrough 的模仿,则可以通过在多个 when 行上接受相同的条件并在条件匹配的地方执行该块来轻松解决。但它不支持它。
t
the Tin Man

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

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 示例(不带参数)来完成,只有这种方法对于这些类型的情况更清洁。


D
DigitalRoss

它被称为 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 替换任意 if/else 链(即,即使测试不涉及公共变量),方法是省略初始 case 参数并只编写表达式,其中第一个匹配是你想要的。

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

t
the Tin Man

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

因此,在 case 语句中,, 相当于 if 语句中的 ||

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

请参阅“How A Ruby Case Statement Works And What You Can Do With It”。


t
the Tin Man

Ruby 使用 case 来编写 switch 语句。

根据 case 文档:

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

例子:

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's case statement - advanced techniques”所描述的 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

t
the Tin Man

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

如果有很长的 when 列表,并且每个都有一个具体的值来比较(不是一个区间),那么声明方法的哈希然后从哈希中调用相关方法会更有效,例如那。

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

P
Peter Mortensen

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

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

P
Peter Mortensen

多值时和无值情况:

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

为什么不只是 case some_string, when /\d/, (stuff), when /[a-zA-Z]/, (stuff), end(其中 , 表示换行符)
哦,第一部分已经包含在 this answer 中,许多答案已经提到了正则表达式。坦率地说,这个答案没有增加任何新内容,我正在投票并投票删除它。
@DoorknobofSnow 这是为了表明您可以在 switch case 中使用正则表达式解决方案和逗号分隔值。不知道为什么这个解决方案让你如此痛苦。
所以如果他们得到一个“F”,一个合法的等级,是他们的错你的代码缺少一个案例吗?
@Doorknob 我也同意这只是对先前答案的重复,但事实上他使用 .match() 方法提出了一个空的 case 确实是 first and previous Regex answer in here 的替代答案。我看不出这种方法如何以及为什么更可取...
t
the Tin Man

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

类似于一系列 if 语句 在 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

尽管您的代码可能会回答这个问题,但您应该至少添加一个简短描述,说明您的代码的作用以及它如何解决最初的问题。
N
Navin

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

case expression
when condtion1
   function
when condition2
   function
else
   function
end

t
the Tin Man

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

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


作为参考,“space-ship”方法是 <=>,它用于根据比较返回小于、等于、大于或不可比较分别返回 -1、0、1 或 nil . Ruby 的 Comparable 模块文档对此进行了解释。
C
Community

如上述许多答案所述,=== 运算符在 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 中的真值。我们很快就会回到这一点。


P
Prabhakar Undurthi
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

P
Peter Mortensen

我已经开始使用:

a = "secondcase"

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

puts var_name
>> "bar"

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


此类代码通常应使用 Hash 而不是 case 语句来完成。
当该开关变大时,使用散列会更快。
t
the Tin Man
$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”。


P
Paulo Belo

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

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 RangesRuby 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

t
the Tin Man

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 并且因为 ',`` 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 值并将其与 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 子句附加多个 && 表达式。


这对我来说似乎不是很好的编码风格。使用罕见的替代语法会不必要地混淆。为什么不使用普通的 if...elsif?您似乎正在尝试混合使用 case 语句和条件。为什么?只需将条件 inside when 块,例如。 when 3; ( x < 2 ) ? 'apple' : 'orange'
C
CPHPython

在您的环境中不支持正则表达式?例如 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,因为 || 的优先级高于 .include?

如果您仍然喜欢使用 ||even though or is preferable in this case,则可以改为:(item.include? 'A') || ...。您可以在此 repl.it 中对其进行测试。


t
the Tin Man

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

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

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


V
Vikrant

我们可以为多个条件编写 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

这行不通; Ruby 关键字(例如 casewhenend)区分大小写,不能像这样大写。
NoMethodError (undefined method CASE' for main:Object)`。正如@sondra.kinsey 所说,您不能使用大写字母。 Ruby 会认为它是一个常数。
M
Moriarty

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

A
AlexSh

我更喜欢用 case + 而不是

number = 10

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