Comment utiliser l'opérateur conditionnel (? :) dans Ruby?

303

Comment l'opérateur conditionnel ( ? :) est-il utilisé dans Ruby?

Par exemple, est-ce correct?

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>
Mithun Sreedharan
la source
1
oui, je pense, mais je pense aussi que vous pourriez y parvenir en: question=question[0,20] s'il était inférieur à 20, cela ne changera rien.
DGM
j'ai également besoin d'ajouter un «...» si la longueur est supérieure à 20
Mithun Sreedharan
1
Soyez prudent en coupant aveuglément une ligne à une colonne donnée. Vous pouvez finir par couper un mot à mi-chemin, puis ajouter l'élipse ('...'), ce qui semble mauvais. À la place, recherchez un signe de ponctuation ou un espace à proximité et tronquez-le. Ce n'est que s'il n'y a pas de meilleur point de rupture à proximité que vous devez tronquer le milieu du mot.
The Tin Man

Réponses:

496

Il s'agit de l' opérateur ternaire , et il fonctionne comme en C (les parenthèses ne sont pas obligatoires). C'est une expression qui fonctionne comme:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

Cependant, en Ruby, ifc'est aussi une expression donc:if a then b else c end === a ? b : c, sauf pour les problèmes de priorité. Les deux sont des expressions.

Exemples:

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

Notez que dans le premier cas, des parenthèses sont requises (sinon Ruby est confus car il pense qu'il est puts if 1 avec des ordures supplémentaires après), mais elles ne sont pas requises dans le dernier cas car ledit problème ne se pose pas.

Vous pouvez utiliser le formulaire "long-if" pour la lisibilité sur plusieurs lignes:

question = if question.size > 20 then
  question.slice(0, 20) + "..."
else 
  question
end
l'homme d'étain
la source
Met 0? 2: 3 donne également 2 comme résultat. Pourquoi donc?
X_Trust
18
@X_Trust Dans Ruby, les seules valeurs de falsification sont nilet false. Pas très habituel, en effet.
Kroltan
35
puts true ? "true" : "false"
=> "true"


puts false ? "true" : "false"
=> "false"
DGM
la source
Terse mais explique ce qu'il fait.
The Tin Man
4
Petit montage puts (true ? "true" : "false")avec parenthèses. Sinon, l'ordre des opérations n'est pas clair. Lorsque j'ai lu ceci pour la première fois, j'étais confus car je l'ai lu car je (puts true) ? "true" : "false"m'attendais putsà retourner le booléen qui est ensuite devenu la valeur de chaîne.
Fresheyeball
26

Votre utilisation d'ERB suggère que vous êtes dans Rails. Si tel est le cas, envisagez truncateun assistant intégré qui fera le travail pour vous:

<% question = truncate(question, :length=>30) %>
Wayne Conrad
la source
C'est bien! ce que je veux exactement faire !!
Mithun Sreedharan
11
C'est des années en retard, mais j'ai été très impressionné par cette réponse car elle a dépassé tous les aspects syntaxiques et est allée directement à ce que le questionneur essayait d'accomplir.
Mike Buckbee
2
+1, mais erb n'implique pas nécessairement des rails (Sinatra, ERB autonome, etc.).
Fox Wilson
17

@pst a donné une excellente réponse, mais je voudrais mentionner que dans Ruby, l'opérateur ternaire est écrit sur une ligne pour être syntaxiquement correct, contrairement à Perl et C où nous pouvons l'écrire sur plusieurs lignes:

(true) ? 1 : 0

Normalement, Ruby génère une erreur si vous essayez de la diviser sur plusieurs lignes, mais vous pouvez utiliser le \symbole de continuation de ligne à la fin d'une ligne et Ruby sera satisfait:

(true)   \
  ? 1    \
  : 0

C'est un exemple simple, mais il peut être très utile lorsqu'il s'agit de lignes plus longues car il garde le code bien présenté.

Il est également possible d'utiliser le ternaire sans les caractères de continuation de ligne en plaçant les opérateurs en dernier sur la ligne, mais je ne l'aime pas ou ne le recommande pas:

(true) ?
  1 :
  0

Je pense que cela conduit à un code très difficile à lire car le test conditionnel et / ou les résultats s'allongent.

J'ai lu des commentaires disant de ne pas utiliser l'opérateur ternaire parce que c'est déroutant, mais c'est une mauvaise raison de ne pas utiliser quelque chose. Par la même logique, nous ne devrions pas utiliser d'expressions régulières, d'opérateurs de plage (' ..' et la variation "flip-flop" apparemment inconnue). Ils sont puissants lorsqu'ils sont utilisés correctement, nous devons donc apprendre à les utiliser correctement.


Pourquoi avez-vous mis des crochets autour true?

Prenons l'exemple du PO:

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

Envelopper le test conditionnel permet de le rendre plus lisible car il sépare visuellement le test:

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

Bien sûr, l'exemple entier pourrait être rendu beaucoup plus lisible en utilisant quelques ajouts judicieux d'espaces. Ceci n'est pas testé mais vous aurez l'idée:

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

Ou, plus écrit de façon plus idiomatique:

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

Il serait facile d'argumenter que la lisibilité en souffre question.questionégalement.

l'homme d'étain
la source
1
Si plusieurs lignes, pourquoi ne pas simplement utiliser si ... sinon ... fin?
Wayne Conrad
1
En raison de trop d'années de travail en Perl et C? J'utilise soit, selon la situation et si l'un est visuellement plus clair que l'autre. Parfois si / sinon est trop verbeux, parfois?: Est moche.
The Tin Man
1
@WayneConrad Le if a au moins un problème expliqué dans cette réponse: stackoverflow.com/a/4252945/2597260 Comparez quelques façons d'utiliser l'opérateur if / ternaire multiligne
Darek Nędza
Pourquoi avez-vous mis des crochets autour true?
Zac
1
Parce que truec'est vraiment une expression qui évalue à trueou false. Il est préférable de les délimiter visuellement, car les déclarations ternaires peuvent rapidement se transformer en bruit visuel, ce qui réduit la lisibilité, ce qui affecte la maintenabilité.
The Tin Man
3

Un exemple simple où l'opérateur vérifie si l'identifiant du joueur est 1 et définit l'identifiant ennemi en fonction du résultat

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

Et j'ai trouvé un article sur le sujet qui semble assez utile.

devwanderer
la source
4
Pourquoi ne pas enemy_id = player_id == 1 ? 2 : 1?
Aaron Blenkush
1
@AaronBlenkush Merci pour cette entrée élégante. Je suis toujours au niveau noob, c'est probablement pourquoi :)
devwanderer
0

Le code condition ? statement_A : statement_Best équivalent à

if condition == true
  statement_A
else
  statement_B
end
Umesh Malhotra
la source
0

Manière la plus simple:

param_a = 1
param_b = 2

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

puisque param_an'est pas égal à param_balors la resultvaleur de seraNot same!

Adrian Eranzi
la source