2009-10-12 11 views
20

Nur kurz, warum sind die folgenden drei Zeilen nicht in ihrer Wirkung identisch?Verständnis der "||" OR-Operator in If-Bedingungen in Ruby

if @controller.controller_name == "projects" || @controller.controller_name == "parts" 

if @controller.controller_name == ("projects" || "parts") 

if @controller.controller_name == "projects" || "parts" 

Die erste gibt mir das Ergebnis, das ich will, aber da es tatsächlich mehr Möglichkeiten gibt als nur Projekte und Teile, das Formular erstellt eine ausführliche Erklärung. Die anderen beiden sind kompakter, aber geben Sie mir nicht das gleiche Ergebnis.

Antwort

38

die genaue Semantik von || sind:

  • , wenn der erste Ausdruck nicht Null oder falsch ist, es zurückgeben
  • , wenn der erste Ausdruck Null oder falsch ist, zurückzukehren, den zweiten Ausdruck

so, was Ihre erste Ausdruck arbeitet, um aus ist Wenn @controller.controller_name == "projects", dann schließt der Ausdruck kurz und liefert true. Wenn nicht, überprüft es den zweiten Ausdruck. die zweite und dritte Variante sind im Wesentlichen if @controller.controller_name == "projects", da "projects" || "parts" gleich "projects" ist. Sie können dies in irb versuchen:

>> "projects" || "parts" 
=> "projects" 

, was Sie ist

if ["projects", "parts"].include? @controller.controller_name 
5

|| auch ein Null-Koaleszenz-Operator ist, so

"projects" || "parts" 

wird die erste Zeichenfolge zurück, die nicht null (in diesem Fall „Projekte“), was bedeutet, dass in den zweiten zwei Beispielen, werden Sie immer evaluieren:

if @controller.controller_name == "projects" 

irb oben abfeuern, können Sie überprüfen, dass dies geschieht:

a = "projects" 
b = "parts" 

a || b 

liefert projects

+4

eigentlich "oder" zwei Strings zusammen ergibt die erste Saite, um Idiome wie 'a || =" hallo "' und 'a = somefunc() || default' zu unterstützen. –

+0

Sie haben absolut Recht. Ich habe meine Antwort aktualisiert. – jerhinesmith

6

Der Unterschied machen wollen, ist die Reihenfolge von dem, was passiert ist. Auch die || tut nicht das, was Sie denken, es die 2 und 3 hat in

Sie auch

if ['projects','parts'].include?(@controller.controller_name) 

tun können Code in die Zukunft zu reduzieren, wenn Sie weitere Spiele hinzufügen müssen.

2

Die einfache Art und Weise eine nicht ausführliche Lösung zu erhalten, ist

if ["a", "b", "c"].include? x 

Dies ist eigentlich nichts mit || zu tun hat, sondern das, was werden die Werte als in Ruby wahr sein. Alles außer falsch und null ist wahr.

0

Zuerst vergleicht man "Projekte" und "Teile" String-Literale mit @controller.controller_name Variable.

Zweite ein auswertet („Projekte“ || „Teile“), die „Projekte“, weil „Projekte“ Stringliteral weder false oder nil oder leerer String und vergleichen Sie es mit @controller.controller_name

Dritte vergleicht man @controller.controller_name und " Projekte "und wenn sie gleich sind, geben sie true zurück, wenn sie nicht sind, geben Sie" Teile "zurück, die true für if Aussage gleich sind.

1

Der logische oder Operator || arbeitet mit booleschen Ausdrücken, so dass es auf Strings nicht tun, was Sie wollen.

Es gibt mehrere Möglichkeiten zu erreichen, was Sie wollen, die weniger ausführlich und lesbarer sind.

Verwendung von Array # include? und eine einfache if-Anweisung:

if ["projects", "parts"].include? @controller.controller_name 
    do_something 
else 
    do_something_else 
end 

Mit einer Fall-Anweisung:

case @controller.controller_name 
when "projects", "parts" then 
    do_something 
else 
    do_something_else 
end 
3

Grundsätzlich == verteilt keine gegenüber anderen Betreibern. Der Grund 3 * (2+1) ist der gleiche wie 3 * 2 + 3 * 1 ist, dass Multiplikation über Addition verteilt.

Der Wert von a || Ausdruck wird eines seiner Argumente sein. Somit entspricht die 2. Aussage:

if @controller.controller_name == "projects" 

|| ist niedriger als precedence ==, so ist die dritte Aussage äquivalent:

if (@controller.controller_name == "projects") || "ports" 
2

Es gibt ein paar los dort verschiedene Dinge:

if @controller.controller_name == "projects" || @controller.controller_name == "parts" 

dies das Verhalten gibt Ihnen Ich gehe davon aus wollen. Die Logik ist ziemlich einfach: true zurück, wenn der Controler Name ist entweder „Projekte“ oder „Teile“

Ein anderer Weg, dies zu tun ist:

if ["projects", "parts", "something else..."].include? @controller.controller_name 

Das überprüft, ob der Controller-Name irgendwo in der ist Liste.

nun für die anderen Beispiele:

if @controller.controller_name == ("projects" || "parts") 

Dies wird nicht das tun, was Sie wollen. Es wird zuerst ("projects" || "parts") ausgewertet (was zu "Projekten" führt), und dann wird nur geprüft, ob der Name des Controllers gleich ist.

if @controller.controller_name == "projects" || "parts" 

Dieser wird noch wackeliger. Dies wird immer zu wahr führen. Es wird zuerst überprüft, ob der Name des Controllers gleich "projects" ist. Wenn dies der Fall ist, wird die Aussage als wahr ausgewertet. Wenn nicht, wertet er "Teile" auf seine eigene Weise aus: was auch in Ruby als "wahr" gilt (jedes nicht-nichtige Objekt wird als "wahr" im Sinne von boolescher Logik betrachtet)