Wie verwende ich den bedingten Operator (? :) in Ruby?

303

Wie wird der bedingte Operator ( ? :) in Ruby verwendet?

Ist das zum Beispiel richtig?

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>
Mithun Sreedharan
quelle
1
Ja, ich denke, aber ich denke auch, dass Sie dies erreichen könnten, indem Sie: question=question[0,20] Wenn es kleiner als 20 wäre, würde es nichts daran ändern.
DGM
Ich muss auch ein '...' hinzufügen, wenn die Länge größer als 20 ist
Mithun Sreedharan
1
Seien Sie vorsichtig, wenn Sie blind eine Zeile an einer bestimmten Spalte abhacken. Sie können am Ende ein Wort auf halbem Weg abschneiden und dann die Elipse ('...') anhängen, was schlecht aussieht. Suchen Sie stattdessen nach einem nahe gelegenen Satzzeichen oder Leerzeichen und schneiden Sie es dort ab. Nur wenn es keine bessere Bruchstelle in der Nähe gibt, sollten Sie das mittlere Wort abschneiden.
der Blechmann

Antworten:

496

Es ist der ternäre Operator und funktioniert wie in C (die Klammern sind nicht erforderlich). Es ist ein Ausdruck, der funktioniert wie:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

In Ruby ifist dies jedoch auch ein Ausdruck: if a then b else c end=== a ? b : c, mit Ausnahme von Vorrangproblemen . Beides sind Ausdrücke.

Beispiele:

puts (if 1 then 2 else 3 end) # => 2

puts 1 ? 2 : 3                # => 2

x = if 1 then 2 else 3 end
puts x                        # => 2

Beachten Sie, dass im ersten Fall Klammern erforderlich sind (andernfalls ist Ruby verwirrt, weil es denkt, dass es sich puts if 1um zusätzlichen Müll handelt), im letzten Fall jedoch nicht, da das Problem nicht auftritt.

Sie können das "Long-If" -Formular zur besseren Lesbarkeit in mehreren Zeilen verwenden:

question = if question.size > 20 then
  question.slice(0, 20) + "..."
else 
  question
end
der Blechmann
quelle
Setzt 0? 2: 3 ergibt auch 2. Warum ist das so?
X_Trust
18
@X_Trust In Ruby sind nilund die einzigen falschen Werte false. In der Tat nicht sehr üblich.
Kroltan
35
puts true ? "true" : "false"
=> "true"


puts false ? "true" : "false"
=> "false"
DGM
quelle
Knapp aber erklärt was es macht.
Der Blechmann
4
Kleine Bearbeitung puts (true ? "true" : "false")mit Klammern. Andernfalls ist die Reihenfolge der Operationen nicht klar. Als ich dies zum ersten Mal las, war ich verwirrt, als ich es wie (puts true) ? "true" : "false"erwartet las puts, um den Booleschen Wert zurückzugeben, der dann zum Zeichenfolgenwert wurde.
Fresheyeball
26

Ihre Verwendung von ERB deutet darauf hin, dass Sie sich in Rails befinden. Wenn ja, dann ziehen Sie truncateeinen eingebauten Helfer in Betracht , der die Arbeit für Sie erledigt:

<% question = truncate(question, :length=>30) %>
Wayne Conrad
quelle
Das ist toll! was ich genau machen will !!
Mithun Sreedharan
11
Dies ist Jahre zu spät, aber ich war sehr beeindruckt von dieser Antwort, da sie alle syntaktischen Aspekte hinter sich ließ und direkt zu dem führte, was der Fragesteller zu erreichen versuchte.
Mike Buckbee
2
+1, aber erb bedeutet nicht unbedingt Schienen (Sinatra, Standalone-ERB usw.).
Fox Wilson
17

@pst gab eine großartige Antwort, aber ich möchte erwähnen, dass in Ruby der ternäre Operator in einer Zeile geschrieben ist, um syntaktisch korrekt zu sein, im Gegensatz zu Perl und C, wo wir ihn in mehreren Zeilen schreiben können:

(true) ? 1 : 0

Normalerweise wird Ruby einen Fehler auslösen, wenn Sie versuchen, ihn auf mehrere Zeilen aufzuteilen. Sie können jedoch das \Zeilenfortsetzungssymbol am Ende einer Zeile verwenden, und Ruby freut sich:

(true)   \
  ? 1    \
  : 0

Dies ist ein einfaches Beispiel, aber es kann sehr nützlich sein, wenn Sie mit längeren Zeilen arbeiten, da der Code übersichtlich bleibt.

Es ist auch möglich, das Ternär ohne die Zeilenfortsetzungszeichen zu verwenden, indem die Operatoren als letzte in die Zeile gesetzt werden, aber ich mag oder empfehle es nicht:

(true) ?
  1 :
  0

Ich denke, das führt zu sehr schwer lesbarem Code, da der bedingte Test und / oder die Ergebnisse länger werden.

Ich habe Kommentare gelesen, in denen es heißt, den ternären Operator nicht zu verwenden, weil er verwirrend ist, aber das ist ein schlechter Grund, etwas nicht zu verwenden. Nach der gleichen Logik sollten wir keine regulären Ausdrücke, Bereichsoperatoren (' ..' und die scheinbar unbekannte "Flip-Flop" -Variante) verwenden. Sie sind mächtig, wenn sie richtig verwendet werden, daher sollten wir lernen, sie richtig zu verwenden.


Warum hast du Klammern gesetzt true?

Betrachten Sie das Beispiel des OP:

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>

Durch das Umschließen des bedingten Tests wird die Lesbarkeit verbessert, da der Test visuell getrennt wird:

<% question = (question.size > 20) ? question.question.slice(0, 20)+"..." : question.question %>

Natürlich könnte das gesamte Beispiel durch einige vernünftige Ergänzungen von Leerzeichen viel lesbarer gemacht werden. Dies ist nicht getestet, aber Sie werden auf die Idee kommen:

<% question = (question.size > 20) ? question.question.slice(0, 20) + "..." \
                                   : question.question 
%>

Oder idiomatischer geschrieben:

<% question = if (question.size > 20)
                question.question.slice(0, 20) + "..."
              else 
                question.question 
              end
%>

Es wäre leicht zu argumentieren, dass die Lesbarkeit ebenfalls stark darunter leidet question.question.

der Blechmann
quelle
1
Wenn mehrzeilig, warum nicht einfach verwenden, wenn ... sonst ... endet?
Wayne Conrad
1
Wegen zu vieler Jahre in Perl und C? Ich benutze entweder je nach Situation und ob einer optisch klarer als der andere ist. Manchmal, wenn / sonst zu ausführlich ist, manchmal ?: Ist hässlich.
der Blechmann
1
@WayneConrad Das if hat mindestens ein Problem, das in dieser Antwort erklärt wurde: stackoverflow.com/a/4252945/2597260 Vergleichen Sie einige Möglichkeiten zur Verwendung des mehrzeiligen if / ternären Operators: gist.github.com/nedzadarek/0f9f99755d42bad10c30
Darek Nędza
Warum hast du Klammern gesetzt true?
Zac
1
Denn truesitzt eigentlich für was wäre ein Ausdruck, der zu trueoder auswertet false. Es ist besser, diese visuell abzugrenzen, da sich ternäre Anweisungen schnell in visuelles Rauschen verwandeln können, wodurch die Lesbarkeit verringert wird, was sich auf die Wartbarkeit auswirkt.
der Blechmann
3

Ein einfaches Beispiel, bei dem der Bediener prüft, ob die ID des Spielers 1 ist, und die ID des Feindes abhängig vom Ergebnis festlegt

player_id=1
....
player_id==1? enemy_id=2 : enemy_id=1
# => enemy=2

Und ich habe einen Beitrag zum Thema gefunden, der ziemlich hilfreich erscheint.

Devwanderer
quelle
4
Warum nicht enemy_id = player_id == 1 ? 2 : 1?
Aaron Blenkush
1
@ AaronBlenkush Danke für die elegante Eingabe. Ich bin immer noch in Noob Level, wahrscheinlich ist es der Grund :)
Devwanderer
0

Der Code condition ? statement_A : statement_Bentspricht

if condition == true
  statement_A
else
  statement_B
end
Umesh Malhotra
quelle
0

Einfachster Weg:

param_a = 1
param_b = 2

result = param_a === param_b ? 'Same!' : 'Not same!'

da param_aist nicht gleich param_bdann wird der resultWert von 'seinNot same!

Adrian Eranzi
quelle