¿Cómo uso el operador condicional (? :) en Ruby?

303

¿Cómo se ? :usa el operador condicional ( ) en Ruby?

Por ejemplo, ¿es esto correcto?

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>
Mithun Sreedharan
fuente
1
Sí, creo, pero también creo que podría lograrlo si: question=question[0,20] Si fuera menor que 20, no lo cambiará.
DGM
También necesito agregar un '...' si la longitud es mayor que 20
Mithun Sreedharan
1
Tenga cuidado de cortar ciegamente una línea en una columna determinada. Puede terminar cortando una palabra a mitad de camino y luego agregando la elipsis ('...'), que se ve mal. En su lugar, busque un signo de puntuación o un espacio en blanco cercano, y trunca allí. Solo si no hay un mejor punto de ruptura cercano, debe truncar a mitad de la palabra.
el Hombre de hojalata

Respuestas:

496

Es el operador ternario , y funciona como en C (no se requieren paréntesis). Es una expresión que funciona así:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

Sin embargo, en Ruby, iftambién es una expresión así: if a then b else c end=== a ? b : c, excepto por cuestiones de precedencia. Ambas son expresiones.

Ejemplos:

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

Tenga en cuenta que en el primer caso se requieren paréntesis (de lo contrario, Ruby se confunde porque cree que es puts if 1con algo de basura adicional después de eso), pero no se requieren en el último caso ya que dicho problema no surge.

Puede usar el formulario "long-if" para facilitar la lectura en varias líneas:

question = if question.size > 20 then
  question.slice(0, 20) + "..."
else 
  question
end
el hombre de hojalata
fuente
Pone 0? 2: 3 también da 2 como resultado. ¿Porqué es eso?
X_Trust
18
@X_Trust En Ruby, los únicos valores falsos son nily false. No muy habitual, de hecho.
Kroltan
35
puts true ? "true" : "false"
=> "true"


puts false ? "true" : "false"
=> "false"
DGM
fuente
Conciso, pero explica lo que hace.
The Tin Man
44
Pequeña edición puts (true ? "true" : "false")con paréntesis. De lo contrario, el orden de las operaciones no está claro. Cuando leí esto por primera vez, estaba confundido cuando lo leí, ya que (puts true) ? "true" : "false"esperaba putsdevolver el booleano que luego se convirtió en el valor de la cadena.
Fresheyeball
26

Su uso de ERB sugiere que está en Rails. Si es así, considere truncateun ayudante incorporado que hará el trabajo por usted:

<% question = truncate(question, :length=>30) %>
Wayne Conrad
fuente
¡Esto es genial! ¡Lo que quiero hacer exactamente!
Mithun Sreedharan
11
Esto lleva años de retraso, pero me impresionó mucho esta respuesta, ya que saltó todos los aspectos sintácticos y fue directo a lo que el interrogador estaba tratando de lograr.
Mike Buckbee 05 de
2
+1, pero erb no implica necesariamente rieles (Sinatra, ERB independiente, etc.).
Fox Wilson
17

@pst dio una gran respuesta, pero me gustaría mencionar que en Ruby el operador ternario está escrito en una línea para ser sintácticamente correcto, a diferencia de Perl y C, donde podemos escribirlo en varias líneas:

(true) ? 1 : 0

Normalmente, Ruby generará un error si intenta dividirlo en varias líneas, pero puede usar el \símbolo de continuación de línea al final de una línea y Ruby estará feliz:

(true)   \
  ? 1    \
  : 0

Este es un ejemplo simple, pero puede ser muy útil cuando se trata de líneas más largas, ya que mantiene el código bien diseñado.

También es posible usar el ternario sin los caracteres de continuación de línea poniendo los operadores en último lugar en la línea, pero no me gusta ni lo recomiendo:

(true) ?
  1 :
  0

Creo que eso lleva a un código realmente difícil de leer a medida que la prueba condicional y / o los resultados se alargan.

He leído comentarios que dicen no usar el operador ternario porque es confuso, pero esa es una mala razón para no usar algo. Por la misma lógica, no deberíamos usar expresiones regulares, operadores de rango (' ..' y la variación aparentemente desconocida de "flip-flop"). Son potentes cuando se usan correctamente, por lo que debemos aprender a usarlos correctamente.


¿Por qué has puesto corchetes true?

Considere el ejemplo del OP:

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

Ajustar la prueba condicional ayuda a que sea más legible porque separa visualmente la prueba:

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

Por supuesto, todo el ejemplo podría hacerse mucho más legible mediante el uso de algunas adiciones juiciosas de espacios en blanco. Esto no se ha probado, pero obtendrá la idea:

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

O, más escrito más idiomáticamente:

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

Sería fácil argumentar que la legibilidad también sufre question.questionmucho.

el hombre de hojalata
fuente
1
Si es multilínea, ¿por qué no usarlo si ... más ... finaliza?
Wayne Conrad el
1
¿Por muchos años trabajando en Perl y C? Yo uso cualquiera, dependiendo de la situación y si uno es visualmente más claro que el otro. A veces si / else es demasiado detallado, a veces?: Es feo.
The Tin Man el
1
@WayneConrad El if tiene al menos un problema explicado en esta respuesta: stackoverflow.com/a/4252945/2597260 Compare algunas formas de usar el operador if / ternary multilínea
Darek Nędza
¿Por qué has puesto corchetes true?
Zac
1
Porque en truerealidad está sentado en lo que sería una expresión que se evalúa como trueo false. Es mejor delimitarlos visualmente, ya que las declaraciones ternarias pueden convertirse rápidamente en ruido visual, reduciendo la legibilidad que afecta la mantenibilidad.
el Hombre de hojalata
3

Un ejemplo simple donde el operador verifica si la identificación del jugador es 1 y establece la identificación del enemigo dependiendo del resultado

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

Y encontré una publicación sobre el tema que parece bastante útil.

devwanderer
fuente
44
¿Por qué no enemy_id = player_id == 1 ? 2 : 1?
Aaron Blenkush
1
@AaronBlenkush Gracias por la elegante aportación. Todavía estoy en el nivel novato, probablemente es por eso :)
devwanderer
0

El código condition ? statement_A : statement_Bes equivalente a

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

La manera más fácil:

param_a = 1
param_b = 2

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

ya param_aque no es igual a param_bentonces el resultvalor de s seráNot same!

Adrian Eranzi
fuente