Как использовать условный оператор (? :) в Ruby?

303

Как условный оператор ( ? :) используется в Ruby?

Например, это правильно?

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>
Митхун Шридхаран
источник
1
да, я думаю, но я также думаю, что вы могли бы сделать это следующим образом: question=question[0,20] если он был меньше 20, это ничего не изменит.
DGM
Мне также нужно добавить «...», если длина больше 20
Митхун Шридхаран,
1
Будьте осторожны, слепо отрубая строку в данном столбце. Вы можете закончить тем, что обрезаете слово на полпути, затем добавляете элипсис («...»), что выглядит плохо. Вместо этого найдите ближайший знак пунктуации или пробела и обрежьте его там. Только если нет лучшего предела поблизости, вы должны урезать среднее слово.
Жестянщик

Ответы:

496

Это троичный оператор , и он работает как в C (круглые скобки не требуются). Это выражение работает так:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

Однако в Ruby ifтакже есть выражение: if a then b else c end=== a ? b : c, за исключением проблем с приоритетами. Оба выражения.

Примеры:

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

Обратите внимание, что в первом случае требуются круглые скобки (в противном случае Ruby путается, потому что думает, что это puts if 1с каким-то дополнительным мусором после него), но они не требуются в последнем случае, так как упомянутая проблема не возникает.

Вы можете использовать форму long-if для удобства чтения на нескольких строках:

question = if question.size > 20 then
  question.slice(0, 20) + "..."
else 
  question
end
жестяной человек
источник
Ставит 0? 2: 3 также дает 2 в результате. Это почему?
X_Trust
18
@X_Trust В Ruby единственными ложными значениями являются nilи false. Не очень обычно, действительно.
Кролтан
35
puts true ? "true" : "false"
=> "true"


puts false ? "true" : "false"
=> "false"
DGM
источник
Кратко, но объясняет, что он делает.
Жестянщик
4
Небольшое редактирование puts (true ? "true" : "false")с круглыми скобками. В противном случае порядок операций неясен. Когда я впервые прочитал это, я был сбит с толку, поскольку я читал это, как (puts true) ? "true" : "false"тогда ожидалось, putsчтобы вернуть логическое значение, которое затем стало строковым значением.
Fresheyeball
26

Ваше использование ERB предполагает, что вы находитесь в Rails. Если это так, то подумайте truncate, встроенный помощник, который сделает эту работу за вас:

<% question = truncate(question, :length=>30) %>
Уэйн Конрад
источник
Это круто! что я точно хочу сделать !!
Mithun Sreedharan
11
Это на несколько лет позже, но я был очень впечатлен этим ответом, так как он перепрыгнул через все синтаксические аспекты и пошел прямо к тому, что пытался выполнить спрашивающий.
Майк Бакби
2
+1, но erb не обязательно подразумевает рельсы (Синатра, автономный ERB и т. Д.).
Фокс Уилсон
17

@pst дал отличный ответ, но я хотел бы отметить, что в Ruby троичный оператор записан в одну строку, чтобы быть синтаксически правильным, в отличие от Perl и C, где мы можем написать его в несколько строк:

(true) ? 1 : 0

Обычно Ruby вызывает ошибку, если вы пытаетесь разбить ее на несколько строк, но вы можете использовать \символ продолжения строки в конце строки, и Ruby будет счастлив:

(true)   \
  ? 1    \
  : 0

Это простой пример, но он может быть очень полезен при работе с более длинными строками, так как он хорошо выкладывает код.

Также возможно использовать троичный без символов продолжения строки, помещая операторы последними в строке, но я не люблю или не рекомендую это:

(true) ?
  1 :
  0

Я думаю, что это приводит к тому, что код становится действительно трудно читать, поскольку условный тест и / или результаты становятся длиннее.

Я читал комментарии о том, что нельзя использовать троичный оператор, потому что это сбивает с толку, но это плохая причина не использовать что-то. По той же логике мы не должны использовать регулярные выражения, операторы диапазона (' ..' и, казалось бы, неизвестный вариант "триггера"). Они эффективны при правильном использовании, поэтому мы должны научиться правильно их использовать.


Почему вы поставили скобки вокруг true?

Рассмотрим пример ОП:

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

Упаковка условного теста помогает сделать его более читабельным, поскольку он визуально разделяет тест:

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

Конечно, весь пример можно сделать намного более читабельным, если использовать некоторые разумные добавления пробелов. Это не проверено, но вы получите идею:

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

Или, более написано более идиоматически:

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

Было бы легко утверждать, что читаемость question.questionтоже сильно страдает .

жестяной человек
источник
1
Если многострочный, почему бы просто не использовать if ... else ... end?
Уэйн Конрад
1
Из-за слишком большого количества лет работы в Perl и C? Я использую либо, в зависимости от ситуации и является ли один визуально более четким, чем другой. Иногда, если / else слишком многословно, иногда?: Уродливо.
Жестянщик
1
@WayneConrad В if есть хотя бы одна проблема, объясненная в этом ответе: stackoverflow.com/a/4252945/2597260 Сравните несколько способов использования многострочного оператора if / ternary: gist.github.com/nedzadarek/0f9f99755d42bad10c30
Nędza
Почему вы поставили скобки вокруг true?
Зак
1
Потому trueчто на самом деле сидит за то, что будет выражением, которое оценивает trueили false. Лучше визуально разграничить их, поскольку троичные операторы могут быстро перерасти в визуальный шум, снижая читабельность, что влияет на удобство обслуживания.
Жестянщик
3

Простой пример, где оператор проверяет, равен ли идентификатор игрока 1, и устанавливает идентификатор врага в зависимости от результата.

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

И я нашел пост на тему, который кажется довольно полезным.

devwanderer
источник
4
Почему нет enemy_id = player_id == 1 ? 2 : 1?
Аарон Бленкуш
1
@AaronBlenkush Спасибо за элегантный вклад. Я все еще на уровне
новичков
0

Код condition ? statement_A : statement_Bэквивалентен

if condition == true
  statement_A
else
  statement_B
end
Умеш Малхотра
источник
0

Самый простой способ:

param_a = 1
param_b = 2

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

так param_aкак не равно, param_bто resultзначение будетNot same!

Адриан Эранци
источник