如何在Ruby中编写一个switch语句

如何在Ruby中编写switch语句?

Ruby使用caseexpression式 。

 case a 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 #{a} -- I have no idea what to do with that." end 

比较是通过使用===运算符将when-clause中的对象与case-clause中的对象进行比较来完成的。 也就是说,它是1..5 === aString === a ,而不是a === 1..5 。 这允许你在上面看到复杂的语义,在这里你可以使用范围和类以及各种各样的东西,而不仅仅是testing相等性。

与许多其他语言的switch语句不同的是,Ruby的case并没有发生,所以when break when不需要结束。 而是像when "foo", "bar"那样为单个指定多个匹配。

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 

将打印“这不是一个string”。

幸运的是,这很容易解决。 ===运算符已被定义,所以如果你在一个类中使用它,并且提供这个类的一个实例作为第二个操作数,它将返回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 

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

这是通过Ruby的情况下完成的。 另请参阅维基百科上的这篇文章 。

引:

 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第一版(O'Reilly)的第123页(我正在使用Kindle)上,它说when子句后面的then关键字可以用换行符或分号代替(就像if then else语法)。 (Ruby 1.8也允许冒号代替…但是这个语法在Ruby 1.9中不再允许。)

情况……当

为了给查克的答案增加更多的例子:

带参数:

 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 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来轻松创build自己的比较器

 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 

(取自“ 可以在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语句如何工作以及如何处理 ”)。

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

这并不完全等价,因为在'b''c'之前不能让'a'执行一段代码,但是大多数情况下,我发现它的相似性足以以相同的方式有用。

您可以使用正则expression式,例如查找stringtypes:

 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示例(不带参数)来完成,只有这种方法对于这些types的案例来说是更清晰的。

如果您渴望知道如何在Ruby开关的情况下使用OR条件:

所以,在一个case语句中,a是||的等价物 在if语句中。

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

Ruby case语句可以做很多其他事情

这就是所谓的case ,它的工作方式就像你所期望的,再加上更多有趣的东西礼貌===实现testing。

 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 

而事实certificate,你也可以通过忽略初始case参数来replace一个任意的if / else链(也就是说,即使这些testing不涉及一个公共variables),只需要写第一个匹配的expression式即可想。

 case when x.nil? ... when (x.match /'^fn'/) ... when (x.include? 'substring') ... when x.gsub('o', 'z') == 'fnzrq' ... when Time.now.tuesday? ... 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 

以下是一个正则expression式解决scheme

 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 

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

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

 # 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语句由一个可选的条件组成,该条件位于case的参数的位置, when从句的位置是零个或多个。 第一个when子句匹配条件(或者评估为布尔真值,如果条件为空)“胜出”,并且其代码段被执行。 case语句的值是when子句的成功值,如果没有这个子句,则为nil

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

例:

 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的博客所描述的那样,

可以与范围一起使用:

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

可以和正则expression式一起使用:

 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 

你可以在ruby中用两种不同的方式编写caseexpression式。

  1. 类似于一系列的“if”语句
  2. 在案例旁边指定一个目标,并将每个“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 

很多很好的答案,但我想我会添加一个factoid。如果你正在试图比较对象(类),确保你有一个太空船的方法(而不是一个笑话),或了解他们如何比较

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

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

 case expression when condtion1 function when condition2 function else function end 
 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 / when语句的底层使用。

以下是关于该操作员的一些额外信息。

案例相等运算符:===

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

 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.换句话说,左边操作数的类将定义===方法的实现是所谓的操作数位置是不可互换的。

正则expression式实现===

如果右侧的string与左侧的正则expression式匹配,则返回true。 / zen / ===“今天练习zazen”#输出:=> true#类似于“今天的练习zazen”=〜/ zen /

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

我已经开始使用:

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

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

 $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 

参考=> https://www.tutorialspoint.com/ruby/ruby_if_else.htm