it-swarm.com.de

Wie schreibe ich eine switch-Anweisung in Ruby

Wie schreibe ich eine switch-Anweisung in Ruby?

1980
Readonly

Ruby verwendet stattdessen den Ausdruck 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 vergleicht das Objekt in der when -Klausel mit dem Objekt in der case -Klausel unter Verwendung des Operators ===. Zum Beispiel 1..5 === x und nicht x === 1..5.

Dies ermöglicht hochentwickelte when -Klauseln, wie oben dargestellt. Bereiche, Klassen und alles Mögliche können auf Gleichheit geprüft werden.

Im Gegensatz zu switch -Anweisungen in vielen anderen Sprachen hat Rubys case kein Fall-through , sodass nicht jeder when mit einem break abgeschlossen werden muss. Sie können auch mehrere Übereinstimmungen in einer einzelnen when-Klausel wie when "foo", "bar" angeben.

2531
Chuck

case...when verhält sich beim Umgang mit Klassen etwas unerwartet. Dies liegt an der Tatsache, dass der Operator === verwendet wird.

Dieser Operator arbeitet wie erwartet mit Literalen, jedoch nicht mit Klassen:

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

Dies bedeutet, dass, wenn Sie einen case ... when über die Klasse eines Objekts ausführen möchten, dies nicht funktioniert:

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

Gibt "Es ist keine Zeichenfolge oder Zahl" aus.

Zum Glück ist dies leicht zu lösen. Der Operator === wurde so definiert, dass er true zurückgibt, wenn Sie ihn mit einer Klasse verwenden und eine Instanz dieser Klasse als zweiten Operanden angeben:

Fixnum === 1 # => true

Kurz gesagt, der obige Code kann durch Entfernen des .class behoben werden:

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

Ich bin heute auf dieses Problem gestoßen, als ich nach einer Antwort gesucht habe, und dies war die erste Seite, die aufgetaucht ist. Daher habe ich mir gedacht, dass dies für andere in der gleichen Situation nützlich sein würde.

423
kikito

Dies erledigt case in Ruby. Siehe auch dieser Artikel auf Wikipedia .

Zitiert:

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

Ein anderes Beispiel:

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

Auf Seite 123 (ich benutze Kindle) von The Ruby Programming Lanugage (1st Edition, O'Reilly) heißt es Das then Schlüsselwort, das auf die when Klauseln folgt, kann durch eine neue Zeile oder ein Semikolon ersetzt werden (genau wie in der if then else Syntax). (In Ruby 1.8 ist auch ein Doppelpunkt anstelle von then zulässig. Diese Syntax ist in Ruby 1.9 jedoch nicht mehr zulässig.)

202

fall ... wenn

Weitere Beispiele zu Chucks Antwort hinzufügen:

Mit Parameter:

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

Ohne Parameter:

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

Bitte beachten Sie das Problem , vor dem Kikito warnt.

94
mmdemirbas

Viele Programmiersprachen, insbesondere die von C abgeleiteten, unterstützen das sogenannte Switch Fallthrough . Ich war auf der Suche nach dem besten Weg, dies auch in Ruby zu tun, und dachte, es könnte für andere nützlich sein:

In C-ähnlichen Sprachen sieht der Fallthrough normalerweise so aus:

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;
}

In Ruby kann dasselbe auf folgende Weise erreicht werden:

case expression
when 'a', 'b', 'c'
  # Do something for a, b or c
when 'd', 'e'
  # Do something else for d or e
end

Dies ist nicht unbedingt gleichbedeutend, da es nicht möglich ist, 'a' einen Codeblock ausführen zu lassen, bevor er zu 'b' oder 'c' durchgeht, aber ich finde es größtenteils ähnlich genug nützlich auf die gleiche Weise.

70
Robert Kajic

In Ruby 2.0 können Sie Lambdas auch wie folgt in case -Anweisungen verwenden:

is_even = ->(x) { x % 2 == 0 }

case number
when 0 then puts 'zero'
when is_even then puts 'even'
else puts 'odd'
end

Sie können auch einfach Ihre eigenen Komparatoren erstellen, indem Sie eine Struktur mit einem benutzerdefinierten === verwenden.

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

(Beispiel aus " Kann procs mit case-Anweisungen in Ruby 2.0 verwendet werden? ".)

Oder mit einer kompletten Klasse:

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

(Beispiel aus " Wie eine Ruby Case-Anweisung funktioniert und was Sie damit tun können ".)

66
James Lim

Sie können reguläre Ausdrücke verwenden, z. B. um einen Typ von Zeichenfolge zu finden:

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

Rubys case wird dafür den Gleichheitsoperanden === verwenden (danke @JimDeville). Zusätzliche Informationen finden Sie unter " Ruby Operators ". Dies kann auch mit dem @ mmdemirbas-Beispiel (ohne Parameter) durchgeführt werden. Nur dieser Ansatz ist für diese Arten von Fällen sauberer.

50
Haris Krajina

Wenn Sie unbedingt wissen möchten, wie eine OR-Bedingung in einem Ruby -Schalter verwendet wird:

Also ist in einer case -Anweisung eine , das Äquivalent zu || in einer if -Anweisung.

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

Viele andere Dinge, die Sie mit einer Ruby case-Anweisung tun können

31

Es heißt case und es funktioniert wie erwartet, plus viel mehr lustiges Zeug mit freundlicher Genehmigung von ===, das die Tests implementiert.

case 5
  when 5
    puts 'yes'
  else
    puts 'else'
end

Nun zum Spaß:

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

Und es stellt sich heraus, dass Sie auch eine beliebige if/else-Kette (auch wenn die Tests keine gemeinsame Variable beinhalten) durch case ersetzen können, indem Sie den anfänglichen case -Parameter weglassen und nur schreiben Ausdrücke, bei denen die erste Übereinstimmung Ihren Wünschen entspricht.

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

Abhängig von Ihrem Fall könnten Sie es vorziehen, einen Hash von Methoden zu verwenden.

Wenn es eine lange Liste von Zeitpunkten gibt und jeder von ihnen einen konkreten Wert zum Vergleichen hat (kein Intervall), ist es effektiver, einen Hash von Methoden zu deklarieren und dann die entsprechende Methode aus dem Hash so aufzurufen.

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

Ruby verwendet case zum Schreiben von switch-Anweisungen.

Gemäß den Ruby-Dokumenten :

Case-Anweisungen bestehen aus einer optionalen Bedingung, die die Position eines Arguments für case hat, und null oder mehr when -Klauseln. Die erste when -Klausel, die mit der Bedingung übereinstimmt (oder, wenn die Bedingung null ist, mit der booleschen Wahrheit bewertet wird), gewinnt, und die Codezeilengruppe wird ausgeführt. Der Wert der case-Anweisung ist der Wert der erfolgreichen when -Klausel oder nil, wenn es keine solche Klausel gibt.

Eine case-Anweisung kann mit einer else -Klausel enden. Jede when Anweisung kann mehrere Kandidatenwerte haben, die durch Kommas getrennt sind.

Beispiel:

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

Kürzere Version:

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

Und wie dieser Blog von Honeybadger Ruby Case beschreibt;

Kann mit Bereichen verwendet werden:

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

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

Kann mit Regex verwendet werden:

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

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

Kann mit Procs und Lambdas verwendet werden:

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

## => "lambdas"

Kann auch mit Ihren eigenen Match-Klassen verwendet werden:

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
20
Lahiru

Da switch case immer ein einzelnes Objekt zurückgibt, können wir dessen Ergebnis direkt ausdrucken:

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

Multi-Value When und No-Value Case:

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

Und hier eine regulärer Ausdruck Lösung:

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
18
123

Sie können in Ruby Fallausdrücke auf zwei verschiedene Arten schreiben.

  1. Ähnlich einer Reihe von "if" -Anweisungen
  2. Geben Sie ein Ziel neben dem Fall an, und jede "when" -Klausel wird mit dem Ziel verglichen.

1. Weg

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

2. Weg

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

Sie können dies auf natürlichere Weise tun,

case expression
when condtion1
   function
when condition2
   function
else
   function
end
9
Navin

Viele gute Antworten, aber ich dachte, ich würde ein Faktoid hinzufügen. Wenn Sie versuchen, Objekte (Klassen) zu vergleichen, stellen Sie sicher, dass Sie eine Raumschiffmethode haben (kein Witz) oder verstehen, wie sie verglichen werden

Hier ist eine gute Diskussion zum Thema http://www.skorks.com/2009/09/Ruby-equality-and-object-comparison/

8
jmansurf
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
5
Prabhakar

Wie in vielen der obigen Antworten angegeben, wird der Operator === bei case/when-Anweisungen unter der Haube verwendet.

Hier sind einige zusätzliche Informationen zu diesem Operator.

Gleichheitsoperator: ===

Viele der in Ruby integrierten Klassen, wie z. B. String, Range und Regexp, bieten eigene Implementierungen des Operators ===, der auch als case-equality, triple equals oder threequals bezeichnet wird. Da es in jeder Klasse unterschiedlich implementiert ist, verhält es sich je nach Art des Objekts, für das es aufgerufen wurde, unterschiedlich. Im Allgemeinen wird true zurückgegeben, wenn das Objekt auf der rechten Seite "gehört" oder "Mitglied" des Objekts auf der linken Seite ist. Beispielsweise kann damit getestet werden, ob ein Objekt eine Instanz einer Klasse (oder einer ihrer Unterklassen) ist.

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

Das gleiche Ergebnis kann mit anderen Methoden erzielt werden, die wahrscheinlich am besten für den Job geeignet sind, wie zum Beispiel is_a? und instance_of ?.

Range Implementierung von ===

Wenn der Operator === für ein Bereichsobjekt aufgerufen wird, wird true zurückgegeben, wenn der rechte Wert in den linken Bereich fällt.

(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

Denken Sie daran, dass der Operator === die Methode === des linken Objekts aufruft. Also ist (1..4) === 3 äquivalent zu (1..4). === 3. Mit anderen Worten, die Klasse des linken Operanden definiert, welche Implementierung der === Methode sein wird aufgerufen, so dass die Operandenpositionen nicht austauschbar sind.

Regexp Implementierung von ===

Gibt true zurück, wenn die Zeichenfolge rechts mit dem regulären Ausdruck links übereinstimmt./zen/=== "Zazen heute üben" # Ausgabe: => true # ist ähnlich wie "Zazen heute üben" = ~/zen /

Der einzige relevante Unterschied zwischen den beiden obigen Beispielen besteht darin, dass === bei einer Übereinstimmung true und = ~ eine Ganzzahl zurückgibt, was in Ruby ein wahrer Wert ist. Wir werden bald darauf zurückkommen.

5
BrunoFacca
$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

3
Navneet

Ich habe angefangen zu benutzen:

a = "secondcase"

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

puts var_name
>> "bar"

In einigen Fällen hilft es, Code zu komprimieren.

1
deepfritz

Es ist wichtig, das Komma ',' in einer when-Klausel als || zu betonen einer if-Anweisung, das heißt, sie führt einen OR-Vergleich durch und keinen AND-Vergleich zwischen den begrenzten Ausdrücken der when-Klausel. Schauen Sie sich also die folgende case-Anweisung an. Natürlich ist x nicht kleiner als 2, aber der Rückgabewert ist 'Apple'. Warum? Da x 3 war und ',' als || fungiert, hat es sich nicht darum gekümmert, den Ausdruck 'x <2' auszuwerten.

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

Sie könnten denken, dass Sie zur Durchführung eines UNDs wie folgt vorgehen können. Aber es geht nicht. Das liegt daran, dass (3 && x> 2) als wahr ausgewertet wird und Ruby den Wert Wahr annimmt und ihn mit === vergleicht, was offensichtlich nicht wahr ist, da x 3 ist.

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

Um einen &&-Vergleich durchzuführen, müssen Sie case like und if else block behandeln:

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

In dem Buch Ruby Programming Language sagt Matz, dass diese letztere Form die einfache (und selten verwendete) Form ist, die nichts weiter als eine alternative Syntax für if/elsif/else ist. Unabhängig davon, ob es selten verwendet wird oder nicht, sehe ich keine andere Möglichkeit, mehrere &&-Ausdrücke für eine bestimmte 'when'-Klausel anzuhängen.

1
Donato

Keine Unterstützung für reguläre Ausdrücke in Ihrer Umgebung? Z.B. Shopify Script Editor (April 2018):

[Fehler]: nicht initialisierte Konstante RegExp

Eine Problemumgehung nach einer Kombination von Methoden, die bereits zuvor in hier und hier behandelt wurden:

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

Ich habe ors in der Klassenmethodenanweisung verwendet, da || eine höhere Priorität hat als .include?. Wenn Sie ein Rubin-Nazi sind, stellen Sie sich bitte vor, ich hätte stattdessen diesen (item.include? 'A') || ... verwendet. repl.it test.

1
CPHPython

Wir können switch-Anweisungen für mehrere Bedingungen schreiben.

Zum Beispiel,

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
1
Foram Thakral