Case-Anweisung mit mehreren Werten in jedem 'when'-Block

314

Ich kann am besten beschreiben, wonach ich suche, indem ich Ihnen den fehlgeschlagenen Code zeige, den ich bisher ausprobiert habe:

case car
  when ['honda', 'acura'].include?(car)
    # code
  when 'toyota' || 'lexus'
    # code
end

Ich habe ungefähr 4 oder 5 verschiedene whenSituationen, die durch ungefähr 50 verschiedene mögliche Werte von ausgelöst werden sollten car. Gibt es eine Möglichkeit, dies mit caseBlöcken zu tun , oder sollte ich einen massiven ifBlock versuchen ?

Nick
quelle

Antworten:

669

In einer caseAnweisung ,entspricht a ||einer ifAnweisung.

case car
   when 'toyota', 'lexus'
      # code
end

Einige andere Dinge, die Sie mit einer Ruby-Fallanweisung tun können

Charles Caldwell
quelle
1
Dieser Link enthält eine bessere Zusammenfassung der case-Anweisungen in Ruby (und enthält auch Beispiele für die Regexp- und Splat-Syntax).
Rsenna
Ich weiß nicht warum, aber diese seltsame Situation passiert: Wenn ich das schreibe: when "toyota", "lexus"bekomme ich : unexpected tSTRING_BEG, expecting keyword_do or '{' or '(' (SyntaxError). Wenn ich dies jedoch schreibe: when "toyota","lexus"funktioniert es. Der einzige Unterschied ist ein Leerzeichen nach dem Komma.
Furkan Ayhan
@ FurkanAyhan Das ist seltsam. Ich habe den Code getestet , um sicherzugehen, dass er funktioniert. Ich vermute, dass in Ihrem Code noch etwas anderes vor sich geht, das einen solchen Fehler verursacht. Ist es möglich, dass Sie vergessen haben, irgendwo eine Zeichenfolge zu schließen oder so etwas?
Charles Caldwell
1
Nun, das funktioniert, aber da Ruby sich auf die Leichtigkeit des Programmierers konzentriert, frage ich mich, warum es Standard || nicht unterstützt oder oder'? Das ist etwas verwirrend
Zia Ul Rehman Mughal
2
Ruby unterstützt oroder ||hier nicht, weil whenrechts davon eine Reihe von durch Kommas getrennten Ausdrücken verwendet wird, keine einzelne Kennung. Aus diesem Grund when a or bist es nicht klar, ob dies als Äquivalent zu when a, boder zu verstehen ist when (a or b), wobei letzterer den Ausdruck a or bzuerst auswertet, bevor er in das Wann geworfen wird. Es ist überraschender und weniger einfach für die Sprache, Token zu haben, die das Verhalten basierend auf dem Kontext ändern, und dann könnten Sie keinen echten orAusdruck auf der rechten Seite eines Wann verwenden.
Taywee
99

Sie können die "Splat" - oder Abflachungssyntax von Ruby nutzen.

Dies macht überwucherte whenKlauseln - Sie müssen ungefähr 10 Werte pro Zweig testen, wenn ich das richtig verstehe - meiner Meinung nach etwas lesbarer. Darüber hinaus können Sie die zu testenden Werte zur Laufzeit ändern. Zum Beispiel:

honda  = ['honda', 'acura', 'civic', 'element', 'fit', ...]
toyota = ['toyota', 'lexus', 'tercel', 'rx', 'yaris', ...]
...

if include_concept_cars
  honda += ['ev-ster', 'concept c', 'concept s', ...]
  ...
end

case car
when *toyota
  # Do something for Toyota cars
when *honda
  # Do something for Honda cars
...
end

Ein anderer gängiger Ansatz wäre die Verwendung eines Hash als Versandtabelle mit Schlüsseln für jeden Wert von carund Werten, die ein aufrufbares Objekt sind, das den Code einschließt, den Sie ausführen möchten.

Pilger
quelle
Dies ist, was ich letztendlich verwendet habe, obwohl ich mich schlecht fühle, wenn ich jemandem das Häkchen wegnehme: D
Nick
Brillante Lösung für lange whenSchlangen. Danke für das Teilen.
Pistos
0

Eine andere gute Möglichkeit, Ihre Logik in Daten einzufügen, ist etwa folgende:

# Initialization.
CAR_TYPES = {
  foo_type: ['honda', 'acura', 'mercedes'],
  bar_type: ['toyota', 'lexus']
  # More...
}
@type_for_name = {}
CAR_TYPES.each { |type, names| names.each { |name| @type_for_name[type] = name } }

case @type_for_name[car]
when :foo_type
  # do foo things
when :bar_type
  # do bar things
end
Hew Wolff
quelle
Ich will nicht unhöflich sein, aber ich habe abgelehnt, weil dies sowohl zeitlich als auch räumlich weniger effizient ist. Es ist auch komplexer und weniger lesbar als die beiden anderen Antworten. Was wäre der Vorteil dieser Methode?
Nick
Es ordnet Ihre gesamte Klassifizierung einem Objekt zu. Sie können jetzt Dinge mit diesem Objekt tun, z. B. es serialisieren und an eine andere Person senden, um Ihre Logik zu erläutern, oder es in einer Datenbank speichern und den Benutzern erlauben, es zu bearbeiten. (Die Logik wird sich ziemlich bald ändern, wenn neue Automodelle herauskommen, oder?) Sie könnten "tischgetrieben" nachschlagen.
Hew Wolff
YAGNI ("Du wirst es nicht brauchen") kann sich hier bewerben. Das Design beeinträchtigt die Zeit- / Raumeffizienz und Lesbarkeit für ein Szenario, das möglicherweise in der Zukunft existiert, aber noch nicht existiert. Die Kosten sind jetzt bezahlt, aber die Belohnung kann niemals geerntet werden.
Nick