如何在Ruby中编写switch语句?
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"
。
根据您的情况,您可能更喜欢使用方法哈希。
如果有一个很长的时间列表,并且每个都有一个具体值要与之比较(而不是间隔),那么声明方法的散列然后从这样的散列调用相关方法会更有效。
# 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])
Ruby使用case
来编写switch语句。
根据Ruby Docs:
案例陈述由一个可选条件组成,该条件位于
case
的参数位置,以及零个或多个when
子句。匹配条件的第一个when
子句(或者如果条件为null则评估为布尔真值)“wins”,并执行其代码节。 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
正如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
由于switch case
总是返回一个对象,我们可以直接打印它的结果:
puts case a
when 0
"It's zero"
when 1
"It's one"
end
多值时和无值情况:
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
您可以在ruby中以两种不同的方式编写案例表达式。
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
你可以用更自然的方式做到这一点,
case expression
when condtion1
function
when condition2
function
else
function
end
很多很好的答案,但我想我会添加一个factoid ..如果你试图比较对象(类)确保你有一个太空船方法(不是一个笑话)或理解他们如何被比较
以下是关于http://www.skorks.com/2009/09/ruby-equality-and-object-comparison/主题的一个很好的讨论
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
正如上面的许多答案中所述,= 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.换句话说,左操作数的类将定义===方法的哪个实现将是调用,因此操作数位置不可互换。
如果右侧的字符串与左侧的正则表达式匹配,则返回true。 / zen / ===“今天练习zazen”#输出:=> true#类似于“今天练习zazen”=〜/ zen /
上面两个例子之间唯一相关的区别是,当匹配时,===返回true而= =返回一个整数,这是Ruby中的真值。我们很快就会回到这里。
$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 => https://www.tutorialspoint.com/ruby/ruby_if_else.htm
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
我今天在寻找答案时遇到了这个问题,这是第一个出现的页面,所以我认为在同样的情况下对其他人有用。
我已经开始使用:
a = "secondcase"
var_name = case a
when "firstcase" then "foo"
when "secondcase" then "bar"
end
puts var_name
>> "bar"
在某些情况下,它有助于压缩代码。
您的环境中不支持正则表达式?例如。 Shopify Script Editor(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?
。如果你是ruby-nazi,请想象我用这个(item.include? 'A') || ...
代替。 repl.it测试。
我们可以为多个条件编写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
在when子句中充当||时,强调逗号','是至关重要的if语句,也就是说,它执行OR比较而不是when子句的分隔表达式之间的AND比较。所以检查以下案例陈述。显然,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进行比较= =,这显然不是真的,因为x是3。
case x
when (3 && x < 2) then 'apple'
when (3 && x > 2) then 'orange'
end
=> nil
要进行&&比较,您必须处理大小写和if 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'子句附加多个&&表达式。
它由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
在Ruby Programming Lanugage(第1版,O'Reilly)的第123页(我正在使用Kindle)上,它说then
子句后面的when
关键字可以用换行符或分号替换(就像在if then else
语法中一样)。 (Ruby 1.8也允许冒号代替then
......但Ruby 1.9中不再允许这种语法。)
要向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。
许多编程语言,特别是那些源自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'
之前执行一段代码,但是在大多数情况下我发现它类似于以相同的方式有用。
在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”。)
您可以使用正则表达式,例如查找字符串类型:
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示例(不带参数)来完成,只有这种方法对于这些类型的情况更清晰。
如果您渴望知道如何在Ruby switch案例中使用OR条件:
因此,在case
声明中,,
相当于||
声明中的if
。
case car
when 'Maruti', 'Hyundai'
# Code here
end
它被称为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