Como uso o operador condicional (? :) no Ruby?

303

Como é o operador condicional (? : ) é usado no Ruby?

Por exemplo, isso está correto?

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>
Mithun Sreedharan
fonte
1
Sim, eu acho, mas também acho que você poderia fazer isso: question=question[0,20] Se fosse menor que 20, não mudaria nada.
DGM 23/11
Eu também preciso adicionar um '...' se o comprimento for superior a 20
Mithun Sreedharan
1
Tenha cuidado cortando cegamente uma linha em uma determinada coluna. Você pode acabar cortando uma palavra no meio do caminho e acrescentando as reticências ('...'), o que parece ruim. Em vez disso, procure um caractere de pontuação ou espaço em branco próximo e trunque lá. Somente se não houver um ponto de interrupção melhor nas proximidades, você deve truncar no meio da palavra.
the Tin Man

Respostas:

496

É o operador ternário e funciona como em C (os parênteses não são necessários). É uma expressão que funciona como:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

No entanto, em Ruby, iftambém é uma expressão assim: if a then b else c end===a ? b : c , exceto para problemas de precedência. Ambos são expressões.

Exemplos:

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

Observe que, no primeiro caso, são necessários parênteses (caso contrário, Ruby fica confuso porque acha que está puts if 1com algum lixo extra depois dele), mas eles não são necessários no último caso, pois o problema não ocorre.

Você pode usar o formulário "long-if" para facilitar a leitura em várias linhas:

question = if question.size > 20 then
  question.slice(0, 20) + "..."
else 
  question
end
o homem de lata
fonte
Coloca 0? 2: 3 também fornece 2 como resultado. Por que é que?
X_Trust
18
@X_Trust No Ruby, os únicos valores de falsy são nile false. Não é muito usual, de fato.
Kroltan
35
puts true ? "true" : "false"
=> "true"


puts false ? "true" : "false"
=> "false"
DGM
fonte
Discreto, mas explica o que faz.
the Tin Man
4
Edição pequena puts (true ? "true" : "false")entre parênteses. Caso contrário, a ordem das operações não é clara. Quando li pela primeira vez, fiquei confuso ao ler o que era (puts true) ? "true" : "false"esperado putspara retornar o booleano que se tornou o valor da string.
Fresheyeball 25/08/15
26

Seu uso do ERB sugere que você esteja no Rails. Em caso afirmativo, considere truncateum auxiliar embutido que fará o trabalho para você:

<% question = truncate(question, :length=>30) %>
Wayne Conrad
fonte
Isso é ótimo! o que eu exatamente quero fazer !!
Mithun Sreedharan 24/11
11
Isso está atrasado anos, mas fiquei muito impressionado com essa resposta, pois ela passou por todos os aspectos sintáticos e foi diretamente ao que o questionador estava tentando realizar.
Mike Buckbee
2
+1, mas erb não implica necessariamente trilhos (Sinatra, ERB autônomo etc.).
Fox Wilson
17

O @pst deu uma ótima resposta, mas eu gostaria de mencionar que em Ruby o operador ternário está escrito em uma linha para estar sintaticamente correto, ao contrário do Perl e C, onde podemos escrevê-lo em várias linhas:

(true) ? 1 : 0

Normalmente, Ruby gera um erro se você tentar dividi-lo em várias linhas, mas você pode usar o \símbolo de continuação de linha no final de uma linha e Ruby ficará feliz:

(true)   \
  ? 1    \
  : 0

Este é um exemplo simples, mas pode ser muito útil para lidar com linhas mais longas, pois mantém o código bem organizado.

Também é possível usar o ternário sem os caracteres de continuação de linha colocando os operadores por último na linha, mas eu não gosto ou recomendo:

(true) ?
  1 :
  0

Eu acho que isso leva a um código realmente difícil de ler à medida que o teste e / ou resultados condicionais ficam mais longos.

Eu li comentários dizendo para não usar o operador ternário porque é confuso, mas esse é um mau motivo para não usar algo. Pela mesma lógica, não devemos usar expressões regulares, operadores de intervalo (' ..' e a variação "flip-flop" aparentemente desconhecida). Eles são poderosos quando usados ​​corretamente, por isso devemos aprender a usá-los corretamente.


Por que você colocou colchetes true?

Considere o exemplo do OP:

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

O agrupamento do teste condicional ajuda a torná-lo mais legível porque separa visualmente o teste:

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

Obviamente, todo o exemplo poderia ser muito mais legível usando algumas adições criteriosas de espaço em branco. Isso não foi testado, mas você terá a ideia:

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

Ou, mais escrito mais idiomaticamente:

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

Seria fácil argumentar que a legibilidade também sofre question.questionmuito.

o homem de lata
fonte
1
Se for multi-linhas, por que não usar apenas se ... mais ... terminar?
Wayne Conrad
1
Por causa de muitos anos trabalhando em Perl e C? Eu também uso, dependendo da situação e se um é visualmente mais claro que o outro. Às vezes, se / else é muito detalhado, às vezes?: É feio.
the Tin Man
1
@WayneConrad O if tem pelo menos um problema explicado nesta resposta: stackoverflow.com/a/4252945/2597260 Compare algumas maneiras de usar o operador se / ternário de várias linhas
Darek Nędza
Por que você colocou colchetes true?
Zac
1
Porque trueestá na verdade substituindo o que seria uma expressão avaliada como trueou false. É melhor delimitar visualmente as declarações, pois as declarações ternárias podem se transformar rapidamente em ruído visual, reduzindo a legibilidade que afeta a capacidade de manutenção.
the Tin Man
3

Um exemplo simples em que o operador verifica se o ID do jogador é 1 e define o ID do inimigo, dependendo do resultado

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

E eu encontrei um post sobre o tópico que parece bastante útil.

devwanderer
fonte
4
Por que não enemy_id = player_id == 1 ? 2 : 1?
Aaron Blenkush 19/03/19
1
@AaronBlenkush Obrigado pela contribuição elegante. Eu ainda estou no nível noob, provavelmente é por isso :)
devwanderer
0

O código condition ? statement_A : statement_Bé equivalente a

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

Caminho mais fácil:

param_a = 1
param_b = 2

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

desde que param_anão seja igual a, param_bentão o resultvalor seráNot same!

Adrian Eranzi
fonte